use mendi::parse::*;
use mendi::wire;
use prost::Message;
#[test]
fn parse_frame_roundtrip() {
let frame = wire::Frame {
acc_x: 100,
acc_y: -200,
acc_z: 300,
ang_x: 10,
ang_y: -20,
ang_z: 30,
temp: 36.5,
ir_l: 50000,
red_l: 40000,
amb_l: 1000,
ir_r: 51000,
red_r: 41000,
amb_r: 1100,
ir_p: 48000,
red_p: 38000,
amb_p: 900,
};
let data = frame.encode_to_vec();
let reading = parse_frame(&data).expect("should decode");
assert_eq!(reading.acc_x, 100);
assert_eq!(reading.acc_y, -200);
assert_eq!(reading.acc_z, 300);
assert_eq!(reading.ang_x, 10);
assert_eq!(reading.ang_y, -20);
assert_eq!(reading.ang_z, 30);
assert!((reading.temperature - 36.5).abs() < 0.01);
assert_eq!(reading.ir_left, 50000);
assert_eq!(reading.red_left, 40000);
assert_eq!(reading.amb_left, 1000);
assert_eq!(reading.ir_right, 51000);
assert_eq!(reading.red_right, 41000);
assert_eq!(reading.amb_right, 1100);
assert_eq!(reading.ir_pulse, 48000);
assert_eq!(reading.red_pulse, 38000);
assert_eq!(reading.amb_pulse, 900);
assert!(reading.timestamp > 0.0);
}
#[test]
fn parse_frame_empty_returns_none() {
assert!(parse_frame(&[]).is_none());
}
#[test]
fn parse_frame_single_field() {
let frame = wire::Frame {
temp: 25.0,
..Default::default()
};
let data = frame.encode_to_vec();
assert!(!data.is_empty()); let reading = parse_frame(&data).expect("should decode");
assert!((reading.temperature - 25.0).abs() < 0.01);
assert_eq!(reading.acc_x, 0); }
#[test]
fn parse_frame_garbage_fails() {
assert!(parse_frame(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).is_none());
}
#[test]
fn is_valid_frame_checks() {
let frame = wire::Frame {
ir_l: 1,
..Default::default()
};
let data = frame.encode_to_vec();
assert!(is_valid_frame(&data));
assert!(!is_valid_frame(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
}
#[test]
fn parse_adc_roundtrip() {
let adc = wire::Adc {
voltage: 3850,
charging: true,
usb: true,
};
let data = adc.encode_to_vec();
let reading = parse_adc(&data).expect("should decode");
assert_eq!(reading.voltage_mv, 3850);
assert!(reading.charging);
assert!(reading.usb_connected);
assert!((reading.voltage() - 3.85).abs() < 0.01);
}
#[test]
fn parse_calibration_roundtrip() {
let cal = wire::Calibration {
offset_l: -5.0,
offset_r: 10.0,
offset_p: 0.5,
enable: true,
low_power_mode: false,
};
let data = cal.encode_to_vec();
let reading = parse_calibration(&data).expect("should decode");
assert!((reading.offset_left - (-5.0)).abs() < 0.01);
assert!((reading.offset_right - 10.0).abs() < 0.01);
assert!((reading.offset_pulse - 0.5).abs() < 0.01);
assert!(reading.auto_calibration);
assert!(!reading.low_power_mode);
}
#[test]
fn parse_diagnostics_with_adc() {
let diag = wire::Diagnostics {
adc: Some(wire::Adc {
voltage: 4000,
charging: false,
usb: true,
}),
imu_ok: true,
sensor_ok: true,
};
let data = diag.encode_to_vec();
let reading = parse_diagnostics(&data).expect("should decode");
assert!(reading.imu_ok);
assert!(reading.sensor_ok);
let adc = reading.adc.expect("should have ADC");
assert_eq!(adc.voltage_mv, 4000);
assert!(!adc.charging);
assert!(adc.usb_connected);
}
#[test]
fn parse_diagnostics_without_adc() {
let diag = wire::Diagnostics {
adc: None,
imu_ok: false,
sensor_ok: true,
};
let data = diag.encode_to_vec();
let reading = parse_diagnostics(&data).expect("should decode");
assert!(!reading.imu_ok);
assert!(reading.sensor_ok);
assert!(reading.adc.is_none());
}
#[test]
fn parse_sensor_roundtrip() {
let sensor = wire::Sensor {
read: true,
address: 0x1A,
data: 0x00ABCDEF,
};
let data = sensor.encode_to_vec();
let reading = parse_sensor(&data).expect("should decode");
assert_eq!(reading.address, 0x1A);
assert_eq!(reading.data, 0x00ABCDEF);
}
#[test]
fn is_valid_frame_empty_rejected() {
assert!(!is_valid_frame(&[]));
}
#[test]
fn parse_adc_all_zeros() {
let adc = wire::Adc {
voltage: 0,
charging: false,
usb: false,
};
let data = adc.encode_to_vec();
let reading = parse_adc(&data).expect("should decode");
assert_eq!(reading.voltage_mv, 0);
assert!(!reading.charging);
assert!(!reading.usb_connected);
assert_eq!(reading.percentage(), 0);
}
#[test]
fn parse_frame_negative_optical_values() {
let frame = wire::Frame {
ir_l: -100,
red_l: -200,
amb_l: -50,
..Default::default()
};
let data = frame.encode_to_vec();
let reading = parse_frame(&data).expect("should decode");
assert_eq!(reading.ir_left, -100);
assert_eq!(reading.red_left, -200);
assert_eq!(reading.amb_left, -50);
}
#[test]
fn parse_frame_max_i32_values() {
let frame = wire::Frame {
acc_x: i32::MAX,
acc_y: i32::MIN,
ir_l: i32::MAX,
..Default::default()
};
let data = frame.encode_to_vec();
let reading = parse_frame(&data).expect("should decode");
assert_eq!(reading.acc_x, i32::MAX);
assert_eq!(reading.acc_y, i32::MIN);
assert_eq!(reading.ir_left, i32::MAX);
}
#[test]
fn parse_calibration_boundary_offsets() {
let cal = wire::Calibration {
offset_l: -127.0,
offset_r: 127.0,
offset_p: -127.0,
enable: false,
low_power_mode: true,
};
let data = cal.encode_to_vec();
let reading = parse_calibration(&data).expect("should decode");
assert!((reading.offset_left - (-127.0)).abs() < 0.01);
assert!((reading.offset_right - 127.0).abs() < 0.01);
assert!(!reading.auto_calibration);
assert!(reading.low_power_mode);
}
#[test]
fn parse_adc_garbage_fails() {
assert!(parse_adc(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).is_none());
}
#[test]
fn parse_calibration_garbage_fails() {
assert!(parse_calibration(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).is_none());
}
#[test]
fn parse_diagnostics_garbage_fails() {
assert!(parse_diagnostics(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).is_none());
}
#[test]
fn parse_sensor_garbage_fails() {
assert!(parse_sensor(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).is_none());
}