use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct DeviceInfoResponse {
pub uuid: Option<String>,
pub manufacturer: Option<String>,
pub model: Option<String>,
pub serial: Option<String>,
pub android_id: Option<String>,
pub device_name: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BatteryInfo {
pub level: Option<f32>,
pub is_charging: Option<bool>,
pub health: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NetworkInfo {
pub ip_address: Option<String>,
pub network_type: Option<String>,
pub mac_address: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageInfo {
pub total_space: u64,
pub free_space: u64,
pub storage_type: Option<String>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DisplayInfo {
pub width: u32,
pub height: u32,
pub scale_factor: f64,
pub refresh_rate: Option<f64>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn device_info_response_default_is_all_none() {
let info = DeviceInfoResponse::default();
assert!(info.uuid.is_none());
assert!(info.manufacturer.is_none());
assert!(info.model.is_none());
assert!(info.serial.is_none());
assert!(info.android_id.is_none());
assert!(info.device_name.is_none());
}
#[test]
fn device_info_response_serializes_correctly() {
let info = DeviceInfoResponse {
uuid: Some("test-uuid".to_string()),
manufacturer: Some("Apple Inc.".to_string()),
model: Some("MacBook Pro".to_string()),
serial: Some("ABC123".to_string()),
android_id: None,
device_name: Some("My Mac".to_string()),
};
let json = serde_json::to_string(&info).unwrap();
assert!(json.contains("test-uuid"));
assert!(json.contains("Apple Inc."));
assert!(json.contains("MacBook Pro"));
}
#[test]
fn device_info_response_deserializes_correctly() {
let json = r#"{
"uuid": "12345",
"manufacturer": "Dell",
"model": "XPS 15",
"serial": null,
"android_id": null,
"device_name": "Work Laptop"
}"#;
let info: DeviceInfoResponse = serde_json::from_str(json).unwrap();
assert_eq!(info.uuid, Some("12345".to_string()));
assert_eq!(info.manufacturer, Some("Dell".to_string()));
assert!(info.serial.is_none());
}
#[test]
fn battery_info_default_is_all_none() {
let battery = BatteryInfo::default();
assert!(battery.level.is_none());
assert!(battery.is_charging.is_none());
assert!(battery.health.is_none());
}
#[test]
fn battery_info_serializes_with_camel_case() {
let battery = BatteryInfo {
level: Some(85.0),
is_charging: Some(true),
health: Some("Good".to_string()),
};
let json = serde_json::to_string(&battery).unwrap();
assert!(json.contains("isCharging"));
assert!(!json.contains("is_charging"));
assert!(json.contains("85"));
}
#[test]
fn battery_info_deserializes_from_camel_case() {
let json = r#"{"level": 50.0, "isCharging": false, "health": "Good"}"#;
let battery: BatteryInfo = serde_json::from_str(json).unwrap();
assert_eq!(battery.level, Some(50.0));
assert_eq!(battery.is_charging, Some(false));
}
#[test]
fn network_info_default_is_all_none() {
let network = NetworkInfo::default();
assert!(network.ip_address.is_none());
assert!(network.network_type.is_none());
assert!(network.mac_address.is_none());
}
#[test]
fn network_info_serializes_with_camel_case() {
let network = NetworkInfo {
ip_address: Some("192.168.1.100".to_string()),
network_type: Some("wifi".to_string()),
mac_address: Some("AA:BB:CC:DD:EE:FF".to_string()),
};
let json = serde_json::to_string(&network).unwrap();
assert!(json.contains("ipAddress"));
assert!(json.contains("networkType"));
assert!(json.contains("macAddress"));
}
#[test]
fn storage_info_default_has_zero_values() {
let storage = StorageInfo::default();
assert_eq!(storage.total_space, 0);
assert_eq!(storage.free_space, 0);
assert!(storage.storage_type.is_none());
}
#[test]
fn storage_info_serializes_with_camel_case() {
let storage = StorageInfo {
total_space: 500_000_000_000, free_space: 100_000_000_000, storage_type: Some("Ssd".to_string()),
};
let json = serde_json::to_string(&storage).unwrap();
assert!(json.contains("totalSpace"));
assert!(json.contains("freeSpace"));
assert!(json.contains("storageType"));
}
#[test]
fn display_info_default_has_zero_values() {
let display = DisplayInfo::default();
assert_eq!(display.width, 0);
assert_eq!(display.height, 0);
assert_eq!(display.scale_factor, 0.0);
assert!(display.refresh_rate.is_none());
}
#[test]
fn display_info_serializes_with_camel_case() {
let display = DisplayInfo {
width: 2560,
height: 1440,
scale_factor: 2.0,
refresh_rate: Some(60.0),
};
let json = serde_json::to_string(&display).unwrap();
assert!(json.contains("scaleFactor"));
assert!(json.contains("refreshRate"));
assert!(json.contains("2560"));
}
#[test]
fn display_info_deserializes_from_camel_case() {
let json = r#"{"width": 1920, "height": 1080, "scaleFactor": 1.0, "refreshRate": 144.0}"#;
let display: DisplayInfo = serde_json::from_str(json).unwrap();
assert_eq!(display.width, 1920);
assert_eq!(display.height, 1080);
assert_eq!(display.refresh_rate, Some(144.0));
}
}