feat: add test protocol
This commit is contained in:
+294
-18
@@ -193,42 +193,318 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn frame(command: u8, payload: Vec<u8>) -> Frame {
|
||||
Frame { command, payload }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acknowledgement() {
|
||||
let frame = Frame { command: 0x01, payload: vec![] };
|
||||
let result = map_response(&frame(0x01, vec![])).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
map_response(&frame).unwrap(),
|
||||
DeviceResponseType::Acknowledgement(Acknowledgement { success: true })
|
||||
result,
|
||||
DeviceResponseType::Acknowledgement(Acknowledgement {
|
||||
success: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_implemented() {
|
||||
let result = map_response(&frame(0x02, vec![])).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::NotImplemented(NotImplemented)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handshake_ack() {
|
||||
let result = map_response(&frame(0x10, vec![0x01])).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::HandshakeAck(HandshakeAck {
|
||||
ack: Some(1)
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handshake_ack_invalid_payload_length() {
|
||||
let result = map_response(&frame(0x10, vec![1, 2]));
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_name() {
|
||||
let result = map_response(&frame(0x13, b"TestDevice".to_vec()))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::DeviceInfo(DeviceInfo {
|
||||
name: "TestDevice".into()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_name_missing_payload() {
|
||||
assert!(
|
||||
map_response(&frame(0x13, vec![]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_name_invalid_ascii() {
|
||||
assert!(
|
||||
map_response(&frame(0x13, vec![0xff]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_preset() {
|
||||
let result = map_response(&frame(0x14, vec![5]))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::CurrentPreset(CurrentPreset {
|
||||
index: 5
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_preset_wrong_length_errors() {
|
||||
let frame = Frame { command: 0x14, payload: vec![1, 2] };
|
||||
assert!(map_response(&frame).is_err());
|
||||
assert!(
|
||||
map_response(&frame(0x14, vec![1, 2]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_command_falls_through() {
|
||||
let frame = Frame { command: 0x99, payload: vec![0xAA] };
|
||||
match map_response(&frame).unwrap() {
|
||||
DeviceResponseType::UnknownResponse(r) => {
|
||||
assert_eq!(r.cmd, "0x99");
|
||||
assert_eq!(r.raw, vec![0xAA]);
|
||||
fn modified_preset() {
|
||||
let payload = vec![0xff; 20];
|
||||
|
||||
let result = map_response(&frame(0x22, payload))
|
||||
.unwrap();
|
||||
|
||||
match result {
|
||||
DeviceResponseType::ModifiedPreset(p) => {
|
||||
assert_eq!(p.modified.len(), 20);
|
||||
assert!(p.modified.iter().all(|v| *v));
|
||||
}
|
||||
other => panic!("expected UnknownResponse, got {:?}", other),
|
||||
other => panic!("unexpected {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modified_preset_invalid_length() {
|
||||
assert!(
|
||||
map_response(&frame(0x22, vec![0; 19]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_chunk() {
|
||||
let result = map_response(&frame(
|
||||
0x24,
|
||||
vec![3, 0xaa, 0xbb],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::ConfigChunk(ConfigChunk {
|
||||
sub_index: 3,
|
||||
data: vec![0xaa, 0xbb],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_chunk_empty_payload_defaults_to_zero() {
|
||||
let frame = Frame { command: 0x24, payload: vec![] };
|
||||
match map_response(&frame).unwrap() {
|
||||
DeviceResponseType::ConfigChunk(c) => {
|
||||
assert_eq!(c.sub_index, 0);
|
||||
assert_eq!(c.data, Vec::<u8>::new());
|
||||
let result = map_response(&frame(0x24, vec![]))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::ConfigChunk(ConfigChunk {
|
||||
sub_index: 0,
|
||||
data: vec![],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_chunk_invalid_index() {
|
||||
assert!(
|
||||
map_response(&frame(0x24, vec![0x1d]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preset_name() {
|
||||
let result = map_response(&frame(
|
||||
0x29,
|
||||
vec![2, b'A', b'm', b'p'],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::PresetName(PresetName {
|
||||
index: 2,
|
||||
name: "Amp".into(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preset_name_missing_index() {
|
||||
assert!(
|
||||
map_response(&frame(0x29, vec![]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preset_name_invalid_ascii() {
|
||||
assert!(
|
||||
map_response(&frame(0x29, vec![1, 0xff]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_flags_locked() {
|
||||
let mut payload = vec![0; 6];
|
||||
payload[5] = 1;
|
||||
|
||||
let result = map_response(&frame(0x2c, payload))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::DeviceFlags(DeviceFlags {
|
||||
is_locked: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_flags_invalid_length() {
|
||||
assert!(
|
||||
map_response(&frame(0x2c, vec![0; 5]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn device_flags_invalid_lock_flag() {
|
||||
let mut payload = vec![0; 6];
|
||||
payload[5] = 2;
|
||||
|
||||
assert!(
|
||||
map_response(&frame(0x2c, payload))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authentication_success() {
|
||||
let result = map_response(&frame(
|
||||
0x2d,
|
||||
vec![0, 1],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
DeviceResponseType::AuthenticationResult(
|
||||
AuthenticationResult {
|
||||
success: true
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authentication_missing_result() {
|
||||
assert!(
|
||||
map_response(&frame(0x2d, vec![0]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authentication_invalid_flag() {
|
||||
assert!(
|
||||
map_response(&frame(0x2d, vec![0, 2]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meters_invalid_length() {
|
||||
assert!(
|
||||
map_response(&frame(0x40, vec![0; 10]))
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn meters_decode() {
|
||||
// 38 bytes required.
|
||||
// First 36 bytes are meter values, remaining 2 bytes ignored.
|
||||
let mut payload = vec![0; 38];
|
||||
|
||||
// half float 1.0 = 0x3c00
|
||||
for i in (0..36).step_by(3) {
|
||||
payload[i] = 0x00;
|
||||
payload[i + 1] = 0x3c;
|
||||
}
|
||||
|
||||
let result = map_response(&frame(0x40, payload))
|
||||
.unwrap();
|
||||
|
||||
match result {
|
||||
DeviceResponseType::Meters(m) => {
|
||||
assert_eq!(m.levels.len(), 12);
|
||||
|
||||
for level in m.levels {
|
||||
assert!(level.is_finite());
|
||||
}
|
||||
}
|
||||
other => panic!("expected ConfigChunk, got {:?}", other),
|
||||
other => panic!("unexpected {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_command_falls_through() {
|
||||
let result = map_response(&frame(
|
||||
0x99,
|
||||
vec![0xaa],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
match result {
|
||||
DeviceResponseType::UnknownResponse(r) => {
|
||||
assert_eq!(r.cmd, "0x99");
|
||||
assert_eq!(r.raw, vec![0xaa]);
|
||||
}
|
||||
other => panic!(
|
||||
"expected UnknownResponse, got {:?}",
|
||||
other
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user