|
|
|
@ -93,6 +93,23 @@ pub fn get_device_types(device: &Device) -> Vec<DeviceType> {
|
|
|
|
mod tests {
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Test helper: builds a Device from service UUIDs and characteristics,
|
|
|
|
|
|
|
|
/// with all other fields stubbed. Tests only exercise classification.
|
|
|
|
|
|
|
|
fn dev(services: &[&str], characteristics: &[&str]) -> Device {
|
|
|
|
|
|
|
|
Device {
|
|
|
|
|
|
|
|
id: "test-device".into(),
|
|
|
|
|
|
|
|
address: "00:00:00:00:00:00".into(),
|
|
|
|
|
|
|
|
display_name: None,
|
|
|
|
|
|
|
|
rssi: None,
|
|
|
|
|
|
|
|
service_uuids: services.iter().map(|s| s.to_string()).collect(),
|
|
|
|
|
|
|
|
characteristics: characteristics.iter().map(|s| s.to_string()).collect(),
|
|
|
|
|
|
|
|
manufacturer_data: None,
|
|
|
|
|
|
|
|
metadata: None,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Real-device fixture: Magene speed/cadence sensor advertising the CSC
|
|
|
|
|
|
|
|
// service (0x1816) as a full 128-bit UUID.
|
|
|
|
#[test]
|
|
|
|
#[test]
|
|
|
|
fn test_service_types_for_magene_speedcadence() {
|
|
|
|
fn test_service_types_for_magene_speedcadence() {
|
|
|
|
let magene = Device {
|
|
|
|
let magene = Device {
|
|
|
|
@ -108,4 +125,101 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&magene), [DeviceType::CadSensor]);
|
|
|
|
assert_eq!(get_device_types(&magene), [DeviceType::CadSensor]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Heart rate
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_hr_sensor_by_service() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&["180d"], &[])), [DeviceType::HrSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_hr_sensor_by_characteristic() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["2a37"])), [DeviceType::HrSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_hr_sensor_by_full_128bit_uuid() {
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
|
|
get_device_types(&dev(&["0000180d-0000-1000-8000-00805f9b34fb"], &[])),
|
|
|
|
|
|
|
|
[DeviceType::HrSensor]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Cadence / speed
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_cadence_by_service() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&["1816"], &[])), [DeviceType::CadSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_cadence_by_characteristic() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["2a5b"])), [DeviceType::CadSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trainer / cycling power / FTMS
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_trainer_by_ftms_service() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&["1826"], &[])), [DeviceType::Trainer]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_trainer_by_power_service() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&["1818"], &[])), [DeviceType::Trainer]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_trainer_by_power_characteristic() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["2a63"])), [DeviceType::Trainer]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_trainer_by_fitness_machine_characteristic() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["2acc"])), [DeviceType::Trainer]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Indoor bike data (2ADx): a trainer characteristic that also implies cadence.
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_indoor_bike_data_is_trainer_and_cadence() {
|
|
|
|
|
|
|
|
// 2ad2 is both a trainer characteristic and an indoor-bike marker.
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
|
|
get_device_types(&dev(&[], &["2ad2"])),
|
|
|
|
|
|
|
|
[DeviceType::Trainer, DeviceType::CadSensor]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_indoor_bike_variant_is_cadence_only() {
|
|
|
|
|
|
|
|
// 2ad5 is an indoor-bike marker but not in the trainer list.
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["2ad5"])), [DeviceType::CadSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// "service::characteristic" strings produced by the scanner.
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_characteristic_split_on_double_colon() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[], &["1816::2a5b"])), [DeviceType::CadSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Combined and negative cases
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_hr_and_cadence_combo() {
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
|
|
get_device_types(&dev(&["180d", "1816"], &[])),
|
|
|
|
|
|
|
|
[DeviceType::HrSensor, DeviceType::CadSensor]
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_battery_service_is_ignored() {
|
|
|
|
|
|
|
|
assert!(get_device_types(&dev(&["180f"], &[])).is_empty());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_empty_device_has_no_types() {
|
|
|
|
|
|
|
|
assert!(get_device_types(&dev(&[], &[])).is_empty());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_uuid_case_and_whitespace_are_normalized() {
|
|
|
|
|
|
|
|
assert_eq!(get_device_types(&dev(&[" 180D "], &[])), [DeviceType::HrSensor]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|