corsairctl/tests/protocol_test.rs
nevaforget c5f8625345 feat: initiale Implementierung von corsairctl
Rust CLI-Tool für Corsair Bragi-Geräte (HS80 RGB Wireless, etc.).
Implementiert Protokoll-Kern, HID-Kommunikation, BragiDevice mit
RAII-Lifecycle, CLI-Subcommands (battery, sidetone, led, info, json,
udev), ALSA-Sidetone-Steuerung und Waybar-JSON-Output.

24 Unit-Tests für Packet-Bau, Response-Parsing und Property-Enums.
2026-03-27 17:34:37 +01:00

153 lines
4.1 KiB
Rust

// ABOUTME: Unit-Tests für Bragi-Protokoll Packet-Bau und Response-Parsing.
// ABOUTME: Testet build_packet, parse_response und BragiResponse-Methoden.
use corsairctl::bragi::protocol::*;
use corsairctl::error::CorsairError;
#[test]
fn build_get_packet_has_correct_header() {
let packet = build_get_packet(ENDPOINT_HEADSET, 0x0F);
assert_eq!(packet[0], 0x00, "Report ID");
assert_eq!(packet[1], PROTOCOL_MARKER, "Protokoll-Marker");
assert_eq!(packet[2], ENDPOINT_HEADSET, "Endpoint");
assert_eq!(packet[3], CMD_GET, "Command");
assert_eq!(packet[4], 0x0F, "Property");
}
#[test]
fn build_get_packet_is_zero_padded() {
let packet = build_get_packet(ENDPOINT_RECEIVER, 0x13);
assert_eq!(packet.len(), PACKET_SIZE);
// Alle Bytes nach der Property sollten 0 sein
for &byte in &packet[5..] {
assert_eq!(byte, 0x00);
}
}
#[test]
fn build_set_packet_includes_data() {
let packet = build_set_packet(ENDPOINT_HEADSET, 0x03, &[0x00, 0x02]);
assert_eq!(packet[3], CMD_SET, "Command");
assert_eq!(packet[4], 0x03, "Property");
assert_eq!(packet[5], 0x00, "Data byte 0");
assert_eq!(packet[6], 0x02, "Data byte 1");
// Rest sollte 0 sein
assert_eq!(packet[7], 0x00);
}
#[test]
fn build_packet_total_size() {
let packet = build_packet(0x08, 0x01, 0x03, &[0x00, 0x02]);
assert_eq!(packet.len(), 65);
}
#[test]
fn parse_response_extracts_fields() {
// Simulierte Response: [marker, status, endpoint, command, data0, data1, ...]
let mut raw = vec![0x02, 0x00, 0x09, 0x02, 0xE8, 0x03];
raw.resize(REPORT_SIZE, 0x00);
let resp = parse_response(&raw).unwrap();
assert_eq!(resp.status, STATUS_OK);
assert_eq!(resp.endpoint, ENDPOINT_HEADSET);
assert_eq!(resp.command, CMD_GET);
assert_eq!(resp.data[0], 0xE8);
assert_eq!(resp.data[1], 0x03);
}
#[test]
fn parse_response_value_u16_little_endian() {
let mut raw = vec![0x02, 0x00, 0x09, 0x02, 0xE8, 0x03];
raw.resize(REPORT_SIZE, 0x00);
let resp = parse_response(&raw).unwrap();
let value = resp.value_u16().unwrap();
// 0xE8 | (0x03 << 8) = 232 + 768 = 1000
assert_eq!(value, 1000);
}
#[test]
fn parse_response_value_u8() {
let mut raw = vec![0x02, 0x00, 0x09, 0x02, 0x03];
raw.resize(REPORT_SIZE, 0x00);
let resp = parse_response(&raw).unwrap();
assert_eq!(resp.value_u8().unwrap(), 0x03);
}
#[test]
fn parse_response_error_f0() {
let raw = vec![0x02, 0xF0, 0x09, 0x02];
let result = parse_response(&raw);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CorsairError::PropertyNotSupported { .. }
));
}
#[test]
fn parse_response_error_f1() {
let raw = vec![0x02, 0xF1, 0x09, 0x02];
let result = parse_response(&raw);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CorsairError::PropertyNotSupported { .. }
));
}
#[test]
fn parse_response_too_short() {
let raw = vec![0x02, 0x00];
let result = parse_response(&raw);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CorsairError::ResponseTooShort { .. }
));
}
#[test]
fn value_u16_on_empty_data_returns_error() {
let raw = vec![0x02, 0x00, 0x09, 0x02]; // Keine Daten-Bytes
let resp = parse_response(&raw).unwrap();
let result = resp.value_u16();
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
CorsairError::ResponseTooShort { expected: 2, got: 0 }
));
}
#[test]
fn battery_level_full_is_1000_promille() {
// Battery Level = 1000 (voll) → 0xE8, 0x03 LE
let mut raw = vec![0x02, 0x00, 0x09, 0x02, 0xE8, 0x03];
raw.resize(REPORT_SIZE, 0x00);
let resp = parse_response(&raw).unwrap();
let promille = resp.value_u16().unwrap();
assert_eq!(promille, 1000);
}
#[test]
fn battery_level_half_is_500_promille() {
// Battery Level = 500 (50%) → 0xF4, 0x01 LE
let mut raw = vec![0x02, 0x00, 0x09, 0x02, 0xF4, 0x01];
raw.resize(REPORT_SIZE, 0x00);
let resp = parse_response(&raw).unwrap();
let promille = resp.value_u16().unwrap();
assert_eq!(promille, 500);
}