use std::fmt;
use busylib::model::storage::{StorageListElement, StorageStatus};
use serde::Serialize;
use crate::reporter::events::CliEvent;
use crate::reporter::events::binary::Payload;
use crate::reporter::events::fields::{field, write_fields};
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct StorageListEvent {
list: Vec<StorageListElement>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct StorageStatusEvent(StorageStatus);
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct StorageReadEvent(Payload);
impl StorageListEvent {
pub fn new(list: Vec<StorageListElement>) -> Self {
Self { list }
}
}
impl StorageStatusEvent {
pub fn new(status: StorageStatus) -> Self {
Self(status)
}
}
impl StorageReadEvent {
pub fn new(payload: Payload) -> Self {
Self(payload)
}
}
impl From<StorageListEvent> for CliEvent {
fn from(event: StorageListEvent) -> Self {
CliEvent::StorageList(event)
}
}
impl From<StorageStatusEvent> for CliEvent {
fn from(event: StorageStatusEvent) -> Self {
CliEvent::StorageStatus(event)
}
}
impl From<StorageReadEvent> for CliEvent {
fn from(event: StorageReadEvent) -> Self {
CliEvent::StorageRead(event)
}
}
impl fmt::Display for StorageListEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (index, element) in self.list.iter().enumerate() {
if index > 0 {
f.write_str("\n")?;
}
match element.size() {
Some(size) => write!(f, "file {} {size}", element.name())?,
None => write!(f, "dir {}", element.name())?,
}
}
Ok(())
}
}
impl fmt::Display for StorageStatusEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let status = &self.0;
let mut fields = Vec::new();
if let Some(used_bytes) = status.used_bytes {
fields.push(field("used bytes", used_bytes));
}
if let Some(free_bytes) = status.free_bytes {
fields.push(field("free bytes", free_bytes));
}
if let Some(total_bytes) = status.total_bytes {
fields.push(field("total bytes", total_bytes));
}
write_fields(f, &fields)
}
}
impl fmt::Display for StorageReadEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
#[test]
fn lists_files_with_their_size_and_directories_without() {
let event = StorageListEvent::new(vec![
StorageListElement::File {
name: ".sys_update.txt".to_string(),
size: 31,
},
StorageListElement::Dir {
name: "apps_data".to_string(),
},
]);
assert_eq!(event.to_string(), "file .sys_update.txt 31\ndir apps_data");
assert_eq!(
serde_json::to_value(CliEvent::from(event)).unwrap(),
json!({
"event": "storage_list",
"list": [
{"type": "file", "name": ".sys_update.txt", "size": 31},
{"type": "dir", "name": "apps_data"}
]
})
);
}
#[test]
fn renders_the_storage_usage() {
let event = StorageStatusEvent::new(StorageStatus {
used_bytes: Some(76087296),
free_bytes: Some(7465435136),
total_bytes: None,
});
assert_eq!(
event.to_string(),
"used bytes: 76087296\nfree bytes: 7465435136"
);
}
#[test]
fn reports_a_read_as_a_file_or_as_base64() {
let written = StorageReadEvent::new(Payload::written(b"payload", "a.png".to_string()));
let inline = StorageReadEvent::new(Payload::inline(b"payload"));
assert_eq!(written.to_string(), "wrote 7 bytes to a.png");
assert_eq!(inline.to_string(), "7 bytes");
assert_eq!(
serde_json::to_value(CliEvent::from(inline)).unwrap(),
json!({"event": "storage_read", "bytes": 7, "base64": "cGF5bG9hZA=="})
);
}
}