use super::event::{RgbEffectsEvent, decode_event};
use super::types::{
ActivityEventType, DisplayPersistencyCapabilities, LedBinIndex, PowerModeTarget,
RgbClusterInfo, RgbDeviceInfo, RgbEffectInfo, RgbExtCapabilities, RgbNvCapabilities,
RgbPersistence, RgbPowerMode, RgbPowerModeConfig, SlotInfoType,
};
#[test]
fn parses_device_info() {
let mut payload = [0; 16];
payload[0] = 0xff;
payload[1] = 0xff;
payload[2] = 2; payload[3..5].copy_from_slice(&0x0001u16.to_be_bytes()); payload[5..7].copy_from_slice(&0x0021u16.to_be_bytes()); payload[7] = 3;
let info = RgbDeviceInfo::from_payload(&payload);
assert_eq!(info.cluster_count, 2);
assert!(
info.nv_capabilities
.contains(RgbNvCapabilities::BOOT_UP_EFFECT)
);
assert!(
info.ext_capabilities
.contains(RgbExtCapabilities::GET_ZONE_EFFECT)
);
assert!(info.ext_capabilities.contains(RgbExtCapabilities::SHUTDOWN));
assert_eq!(info.multicluster_effect_count, 3);
}
#[test]
fn parses_cluster_info() {
let mut payload = [0; 16];
payload[0] = 1;
payload[2..4].copy_from_slice(&2u16.to_be_bytes()); payload[4] = 5; payload[5] = 0b101; payload[6] = 1; payload[7] = 0;
let info = RgbClusterInfo::from_payload(&payload);
assert_eq!(info.cluster_index, 1);
assert_eq!(info.location, 2);
assert_eq!(info.effects_number, 5);
assert!(
info.display_persistency
.contains(DisplayPersistencyCapabilities::ALWAYS_ON)
);
assert!(
info.display_persistency
.contains(DisplayPersistencyCapabilities::ON_THEN_OFF)
);
assert!(info.effect_persistency);
assert!(!info.multiled_pattern);
}
#[test]
fn parses_effect_info() {
let mut payload = [0; 16];
payload[0] = 0;
payload[1] = 1;
payload[2..4].copy_from_slice(&4u16.to_be_bytes()); payload[4..6].copy_from_slice(&0x0007u16.to_be_bytes());
payload[6..8].copy_from_slice(&500u16.to_be_bytes());
let info = RgbEffectInfo::from_payload(&payload);
assert_eq!(info.cluster_effect_index, 1);
assert_eq!(info.effect_id, 4);
assert_eq!(info.effect_capabilities, 0x0007);
assert_eq!(info.effect_period, 500);
}
#[test]
fn parses_power_mode_config() {
let mut payload = [0; 16];
payload[0] = 0; payload[1..3].copy_from_slice(&0x0003u16.to_be_bytes());
payload[3..5].copy_from_slice(&60u16.to_be_bytes());
payload[5..7].copy_from_slice(&300u16.to_be_bytes());
let config = RgbPowerModeConfig::from_payload(&payload);
assert_eq!(config.flags, 0x0003);
assert_eq!(config.no_activity_timeout_to_power_save, 60);
assert_eq!(config.no_activity_timeout_to_off, 300);
}
#[test]
fn decodes_effect_sync_event() {
let mut payload = [0; 16];
payload[0] = 0xff;
payload[1..3].copy_from_slice(&2000u16.to_be_bytes());
assert_eq!(
decode_event(0, &payload),
Some(RgbEffectsEvent::EffectSync {
cluster_index: 0xff,
effect_counter: 2000,
})
);
}
#[test]
fn decodes_user_activity_event() {
let mut payload = [0; 16];
payload[0] = 1;
assert_eq!(
decode_event(1, &payload),
Some(RgbEffectsEvent::UserActivity(
ActivityEventType::UserActivityDetected
))
);
}
#[test]
fn decodes_cluster_changed_event() {
let mut payload = [0; 16];
payload[0] = 1;
payload[1] = 2;
payload[2..12].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
payload[12] = 0b101;
assert_eq!(
decode_event(2, &payload),
Some(RgbEffectsEvent::ClusterChanged {
cluster_index: 1,
cluster_effect_index: 2,
params: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
persistence: RgbPersistence::VOLATILE,
power_mode: Some(PowerModeTarget::PowerSave),
})
);
}
#[test]
fn ignores_unknown_event_sub_id() {
assert!(decode_event(7, &[0; 16]).is_none());
}
#[test]
fn maps_stable_enum_wire_values() {
assert_eq!(RgbPowerMode::try_from(1u8).unwrap(), RgbPowerMode::FullRgb);
assert_eq!(RgbPowerMode::try_from(3u8).unwrap(), RgbPowerMode::PowerOff);
assert!(RgbPowerMode::try_from(0u8).is_err());
assert_eq!(u8::from(PowerModeTarget::PowerSave), 1);
assert_eq!(
LedBinIndex::try_from(2u8).unwrap(),
LedBinIndex::CalibrationFactors
);
assert_eq!(
SlotInfoType::try_from(6u8).unwrap(),
SlotInfoType::EffectName21To31
);
assert!(SlotInfoType::try_from(7u8).is_err());
}
#[test]
fn keeps_user_activity_event_with_unknown_type() {
for byte in 0..=u8::MAX {
let mut payload = [0; 16];
payload[0] = byte;
assert_eq!(
decode_event(1, &payload),
Some(RgbEffectsEvent::UserActivity(ActivityEventType::from(byte))),
"dropped user-activity event for byte {byte:#04x}"
);
}
}
#[test]
fn keeps_cluster_changed_event_with_unknown_power_mode() {
for flags in 0..=u8::MAX {
let mut payload = [0; 16];
payload[0] = 1; payload[12] = flags;
let event = decode_event(2, &payload)
.unwrap_or_else(|| panic!("dropped cluster-changed event for flags {flags:#04x}"));
let RgbEffectsEvent::ClusterChanged { cluster_index, .. } = event else {
panic!("expected ClusterChanged");
};
assert_eq!(cluster_index, 1);
}
}