Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/ZWave.CommandClasses.Tests/AssociationCommandClassTests.Modify.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
namespace ZWave.CommandClasses.Tests;

public partial class AssociationCommandClassTests
{
[TestMethod]
public void SetCommand_Create_WithNodeIds()
{
AssociationCommandClass.AssociationSetCommand command =
AssociationCommandClass.AssociationSetCommand.Create(1, new byte[] { 2, 3 });

Assert.AreEqual(CommandClassId.Association, AssociationCommandClass.AssociationSetCommand.CommandClassId);
Assert.AreEqual((byte)AssociationCommand.Set, AssociationCommandClass.AssociationSetCommand.CommandId);

// CC + Cmd + GroupId + NodeID(2) + NodeID(3) = 5 bytes
Assert.AreEqual(5, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)1, parameters[0]); // GroupId
Assert.AreEqual((byte)2, parameters[1]); // NodeID 1
Assert.AreEqual((byte)3, parameters[2]); // NodeID 2
}

[TestMethod]
public void SetCommand_Create_NoNodeIds()
{
AssociationCommandClass.AssociationSetCommand command =
AssociationCommandClass.AssociationSetCommand.Create(1, Array.Empty<byte>());

// CC + Cmd + GroupId = 3 bytes
Assert.AreEqual(3, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)1, parameters[0]); // GroupId
}

[TestMethod]
public void SetCommand_Create_SingleNodeId()
{
AssociationCommandClass.AssociationSetCommand command =
AssociationCommandClass.AssociationSetCommand.Create(5, new byte[] { 10 });

// CC + Cmd + GroupId + NodeID = 4 bytes
Assert.AreEqual(4, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)5, parameters[0]); // GroupId
Assert.AreEqual((byte)10, parameters[1]); // NodeID
}

[TestMethod]
public void RemoveCommand_Create_SpecificNodeIdFromGroup()
{
AssociationCommandClass.AssociationRemoveCommand command =
AssociationCommandClass.AssociationRemoveCommand.Create(3, new byte[] { 5 });

Assert.AreEqual(CommandClassId.Association, AssociationCommandClass.AssociationRemoveCommand.CommandClassId);
Assert.AreEqual((byte)AssociationCommand.Remove, AssociationCommandClass.AssociationRemoveCommand.CommandId);

ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)3, parameters[0]); // GroupId
Assert.AreEqual((byte)5, parameters[1]); // NodeID
}

[TestMethod]
public void RemoveCommand_Create_AllFromGroup()
{
// GroupId > 0, no NodeIDs → remove all from group
AssociationCommandClass.AssociationRemoveCommand command =
AssociationCommandClass.AssociationRemoveCommand.Create(3, Array.Empty<byte>());

// CC + Cmd + GroupId = 3 bytes
Assert.AreEqual(3, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)3, parameters[0]); // GroupId
}

[TestMethod]
public void RemoveCommand_Create_AllFromAllGroups_V2()
{
// GroupId = 0, no NodeIDs → remove all from all groups (V2+)
AssociationCommandClass.AssociationRemoveCommand command =
AssociationCommandClass.AssociationRemoveCommand.Create(0, Array.Empty<byte>());

Assert.AreEqual(3, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)0, parameters[0]); // GroupId = 0
}

[TestMethod]
public void RemoveCommand_Create_SpecificNodeIdFromAllGroups_V2()
{
// GroupId = 0, with NodeIDs → remove from all groups (V2+)
AssociationCommandClass.AssociationRemoveCommand command =
AssociationCommandClass.AssociationRemoveCommand.Create(0, new byte[] { 7 });

ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)0, parameters[0]); // GroupId = 0
Assert.AreEqual((byte)7, parameters[1]); // NodeID
}

[TestMethod]
public void RemoveCommand_Create_MultipleNodeIdsFromGroup()
{
AssociationCommandClass.AssociationRemoveCommand command =
AssociationCommandClass.AssociationRemoveCommand.Create(2, new byte[] { 3, 4, 5 });

// CC + Cmd + GroupId + 3 NodeIDs = 6 bytes
Assert.AreEqual(6, command.Frame.Data.Length);
ReadOnlySpan<byte> parameters = command.Frame.CommandParameters.Span;
Assert.AreEqual((byte)2, parameters[0]); // GroupId
Assert.AreEqual((byte)3, parameters[1]); // NodeID 1
Assert.AreEqual((byte)4, parameters[2]); // NodeID 2
Assert.AreEqual((byte)5, parameters[3]); // NodeID 3
}
}
140 changes: 140 additions & 0 deletions src/ZWave.CommandClasses.Tests/AssociationCommandClassTests.Report.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using Microsoft.Extensions.Logging.Abstractions;

namespace ZWave.CommandClasses.Tests;

public partial class AssociationCommandClassTests
{
[TestMethod]
public void GetCommand_Create_HasCorrectFormat()
{
AssociationCommandClass.AssociationGetCommand command =
AssociationCommandClass.AssociationGetCommand.Create(3);

Assert.AreEqual(CommandClassId.Association, AssociationCommandClass.AssociationGetCommand.CommandClassId);
Assert.AreEqual((byte)AssociationCommand.Get, AssociationCommandClass.AssociationGetCommand.CommandId);
Assert.AreEqual(3, command.Frame.Data.Length); // CC + Cmd + GroupId
Assert.AreEqual((byte)3, command.Frame.CommandParameters.Span[0]);
}

[TestMethod]
public void Report_ParseInto_NodeIdDestinations()
{
// CC=0x85, Cmd=0x03, GroupId=1, MaxNodes=5, ReportsToFollow=0, NodeID=2, NodeID=3
byte[] data = [0x85, 0x03, 0x01, 0x05, 0x00, 0x02, 0x03];
CommandClassFrame frame = new(data);

List<byte> nodeIdDestinations = [];
(byte maxNodesSupported, byte reportsToFollow) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame, nodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)5, maxNodesSupported);
Assert.AreEqual((byte)0, reportsToFollow);
Assert.HasCount(2, nodeIdDestinations);
Assert.AreEqual((byte)2, nodeIdDestinations[0]);
Assert.AreEqual((byte)3, nodeIdDestinations[1]);
}

[TestMethod]
public void Report_ParseInto_EmptyDestinations()
{
// CC=0x85, Cmd=0x03, GroupId=1, MaxNodes=5, ReportsToFollow=0, no destinations
byte[] data = [0x85, 0x03, 0x01, 0x05, 0x00];
CommandClassFrame frame = new(data);

List<byte> nodeIdDestinations = [];
(byte maxNodesSupported, byte reportsToFollow) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame, nodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)5, maxNodesSupported);
Assert.AreEqual((byte)0, reportsToFollow);
Assert.IsEmpty(nodeIdDestinations);
}

[TestMethod]
public void Report_ParseInto_ReportsToFollow()
{
// CC=0x85, Cmd=0x03, GroupId=1, MaxNodes=20, ReportsToFollow=2, NodeID=1
byte[] data = [0x85, 0x03, 0x01, 0x14, 0x02, 0x01];
CommandClassFrame frame = new(data);

List<byte> nodeIdDestinations = [];
(byte maxNodesSupported, byte reportsToFollow) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame, nodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)20, maxNodesSupported);
Assert.AreEqual((byte)2, reportsToFollow);
Assert.HasCount(1, nodeIdDestinations);
Assert.AreEqual((byte)1, nodeIdDestinations[0]);
}

[TestMethod]
public void Report_ParseInto_TooShort_Throws()
{
// Only 2 parameter bytes, need at least 3 (GroupId + MaxNodes + ReportsToFollow)
byte[] data = [0x85, 0x03, 0x01, 0x05];
CommandClassFrame frame = new(data);

List<byte> nodeIdDestinations = [];
Assert.Throws<ZWaveException>(
() => AssociationCommandClass.AssociationReportCommand.ParseInto(
frame, nodeIdDestinations, NullLogger.Instance));
}

[TestMethod]
public void Report_ParseInto_MultiFrameAggregation()
{
// Frame 1: GroupId=1, MaxNodes=20, ReportsToFollow=1, NodeID=1, NodeID=2
byte[] data1 = [0x85, 0x03, 0x01, 0x14, 0x01, 0x01, 0x02];
CommandClassFrame frame1 = new(data1);

// Frame 2: GroupId=1, MaxNodes=20, ReportsToFollow=0, NodeID=3
byte[] data2 = [0x85, 0x03, 0x01, 0x14, 0x00, 0x03];
CommandClassFrame frame2 = new(data2);

List<byte> allNodeIdDestinations = [];

(byte maxNodesSupported1, byte reportsToFollow1) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame1, allNodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)20, maxNodesSupported1);
Assert.AreEqual((byte)1, reportsToFollow1);

(byte maxNodesSupported2, byte reportsToFollow2) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame2, allNodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)20, maxNodesSupported2);
Assert.AreEqual((byte)0, reportsToFollow2);

// Combined result: 3 NodeID destinations
Assert.HasCount(3, allNodeIdDestinations);
Assert.AreEqual((byte)1, allNodeIdDestinations[0]);
Assert.AreEqual((byte)2, allNodeIdDestinations[1]);
Assert.AreEqual((byte)3, allNodeIdDestinations[2]);
}

[TestMethod]
public void Report_ParseInto_ManyNodes()
{
// CC=0x85, Cmd=0x03, GroupId=1, MaxNodes=10, ReportsToFollow=0, NodeID=1..5
byte[] data = [0x85, 0x03, 0x01, 0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
CommandClassFrame frame = new(data);

List<byte> nodeIdDestinations = [];
(byte maxNodesSupported, byte reportsToFollow) =
AssociationCommandClass.AssociationReportCommand.ParseInto(
frame, nodeIdDestinations, NullLogger.Instance);

Assert.AreEqual((byte)10, maxNodesSupported);
Assert.AreEqual((byte)0, reportsToFollow);
Assert.HasCount(5, nodeIdDestinations);
for (int i = 0; i < 5; i++)
{
Assert.AreEqual((byte)(i + 1), nodeIdDestinations[i]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.Extensions.Logging.Abstractions;

namespace ZWave.CommandClasses.Tests;

public partial class AssociationCommandClassTests
{
[TestMethod]
public void SpecificGroupGetCommand_Create_HasCorrectFormat()
{
AssociationCommandClass.AssociationSpecificGroupGetCommand command =
AssociationCommandClass.AssociationSpecificGroupGetCommand.Create();

Assert.AreEqual(
CommandClassId.Association,
AssociationCommandClass.AssociationSpecificGroupGetCommand.CommandClassId);
Assert.AreEqual(
(byte)AssociationCommand.SpecificGroupGet,
AssociationCommandClass.AssociationSpecificGroupGetCommand.CommandId);
Assert.AreEqual(2, command.Frame.Data.Length); // CC + Cmd only
}

[TestMethod]
public void SpecificGroupReport_Parse_ValidGroup()
{
// CC=0x85, Cmd=0x0C, Group=3
byte[] data = [0x85, 0x0C, 0x03];
CommandClassFrame frame = new(data);

byte group = AssociationCommandClass.AssociationSpecificGroupReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)3, group);
}

[TestMethod]
public void SpecificGroupReport_Parse_NotSupported()
{
// CC=0x85, Cmd=0x0C, Group=0 (not supported or no recent button)
byte[] data = [0x85, 0x0C, 0x00];
CommandClassFrame frame = new(data);

byte group = AssociationCommandClass.AssociationSpecificGroupReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)0, group);
}

[TestMethod]
public void SpecificGroupReport_Parse_MaxGroup()
{
// CC=0x85, Cmd=0x0C, Group=255
byte[] data = [0x85, 0x0C, 0xFF];
CommandClassFrame frame = new(data);

byte group = AssociationCommandClass.AssociationSpecificGroupReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)255, group);
}

[TestMethod]
public void SpecificGroupReport_Parse_TooShort_Throws()
{
// CC=0x85, Cmd=0x0C, no parameters
byte[] data = [0x85, 0x0C];
CommandClassFrame frame = new(data);

Assert.Throws<ZWaveException>(
() => AssociationCommandClass.AssociationSpecificGroupReportCommand.Parse(
frame, NullLogger.Instance));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.Extensions.Logging.Abstractions;

namespace ZWave.CommandClasses.Tests;

public partial class AssociationCommandClassTests
{
[TestMethod]
public void SupportedGroupingsGetCommand_Create_HasCorrectFormat()
{
AssociationCommandClass.AssociationSupportedGroupingsGetCommand command =
AssociationCommandClass.AssociationSupportedGroupingsGetCommand.Create();

Assert.AreEqual(
CommandClassId.Association,
AssociationCommandClass.AssociationSupportedGroupingsGetCommand.CommandClassId);
Assert.AreEqual(
(byte)AssociationCommand.SupportedGroupingsGet,
AssociationCommandClass.AssociationSupportedGroupingsGetCommand.CommandId);
Assert.AreEqual(2, command.Frame.Data.Length); // CC + Cmd only
}

[TestMethod]
public void SupportedGroupingsReport_Parse_ValidFrame()
{
// CC=0x85, Cmd=0x06, SupportedGroupings=5
byte[] data = [0x85, 0x06, 0x05];
CommandClassFrame frame = new(data);

byte groupings = AssociationCommandClass.AssociationSupportedGroupingsReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)5, groupings);
}

[TestMethod]
public void SupportedGroupingsReport_Parse_SingleGroup()
{
// CC=0x85, Cmd=0x06, SupportedGroupings=1
byte[] data = [0x85, 0x06, 0x01];
CommandClassFrame frame = new(data);

byte groupings = AssociationCommandClass.AssociationSupportedGroupingsReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)1, groupings);
}

[TestMethod]
public void SupportedGroupingsReport_Parse_MaxGroups()
{
// CC=0x85, Cmd=0x06, SupportedGroupings=255
byte[] data = [0x85, 0x06, 0xFF];
CommandClassFrame frame = new(data);

byte groupings = AssociationCommandClass.AssociationSupportedGroupingsReportCommand.Parse(
frame, NullLogger.Instance);

Assert.AreEqual((byte)255, groupings);
}

[TestMethod]
public void SupportedGroupingsReport_Parse_TooShort_Throws()
{
// CC=0x85, Cmd=0x06, no parameters
byte[] data = [0x85, 0x06];
CommandClassFrame frame = new(data);

Assert.Throws<ZWaveException>(
() => AssociationCommandClass.AssociationSupportedGroupingsReportCommand.Parse(
frame, NullLogger.Instance));
}
}
Loading