use std::io::{self, Write};
pub fn format_size(value: u64) -> String {
format_size_f64(value as f64)
}
pub fn format_size_f64(value: f64) -> String {
const TB: f64 = 1_000_000_000_000.0;
const GB: f64 = 1_000_000_000.0;
const MB: f64 = 1_000_000.0;
const KB: f64 = 1_000.0;
if value >= TB {
format!("{:.2} TB", value / TB)
} else if value >= GB {
format!("{:.2} GB", value / GB)
} else if value >= MB {
format!("{:.2} MB", value / MB)
} else if value >= KB {
format!("{:.2} KB", value / KB)
} else {
format!("{:.0} B", value)
}
}
pub fn format_api_size(size: &wme_models::metadata::Size) -> String {
if size.value >= 100.0 {
format!("{:.0} {}", size.value, size.unit_text)
} else if size.value >= 10.0 {
format!("{:.1} {}", size.value, size.unit_text)
} else {
format!("{:.2} {}", size.value, size.unit_text)
}
}
pub fn build_params(
opts: &crate::commands::GlobalOpts,
) -> anyhow::Result<Option<wme_models::RequestParams>> {
let mut params = wme_models::RequestParams::default();
if let Some(fields_str) = &opts.fields {
let fields: Vec<String> = fields_str
.split(',')
.map(|s| s.trim().to_string())
.collect();
params.fields = Some(fields);
}
if !opts.filter.is_empty() {
let mut filters = Vec::new();
for filter in &opts.filter {
if let Some((field, value)) = filter.split_once('=') {
filters.push(wme_models::Filter {
field: field.to_string(),
value: wme_models::FilterValue::String(value.to_string()),
});
} else {
anyhow::bail!("Invalid filter format: {}. Expected field=value", filter);
}
}
params.filters = Some(filters);
}
if let Some(limit) = opts.limit {
params.limit = Some(limit as u32);
}
if params.fields.is_some() || params.filters.is_some() || params.limit.is_some() {
Ok(Some(params))
} else {
Ok(None)
}
}
pub fn prompt_username(prompt: &str) -> anyhow::Result<String> {
print!("{}", prompt);
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Ok(input.trim().to_string())
}
pub fn prompt_password(prompt: &str) -> anyhow::Result<String> {
let password = rpassword::prompt_password(prompt)?;
Ok(password)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::GlobalOpts;
use crate::config::Config;
use crate::output::OutputFormat;
#[test]
fn test_format_size_bytes() {
assert_eq!(format_size(500), "500 B");
assert_eq!(format_size(0), "0 B");
assert_eq!(format_size(999), "999 B");
}
#[test]
fn test_format_size_kilobytes() {
assert_eq!(format_size(1_000), "1.00 KB");
assert_eq!(format_size(1_500), "1.50 KB");
assert_eq!(format_size(999_999), "1000.00 KB");
}
#[test]
fn test_format_size_megabytes() {
assert_eq!(format_size(1_000_000), "1.00 MB");
assert_eq!(format_size(1_500_000), "1.50 MB");
assert_eq!(format_size(999_999_999), "1000.00 MB");
}
#[test]
fn test_format_size_gigabytes() {
assert_eq!(format_size(1_000_000_000), "1.00 GB");
assert_eq!(format_size(1_500_000_000), "1.50 GB");
assert_eq!(format_size(999_999_999_999), "1000.00 GB");
}
#[test]
fn test_format_size_terabytes() {
assert_eq!(format_size(1_000_000_000_000), "1.00 TB");
assert_eq!(format_size(1_500_000_000_000), "1.50 TB");
}
#[test]
fn test_build_params_empty() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: None,
filter: vec![],
limit: None,
config: Config::default(),
};
let params = build_params(&opts).unwrap();
assert!(params.is_none());
}
#[test]
fn test_build_params_with_fields() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: Some("name,url,abstract".to_string()),
filter: vec![],
limit: None,
config: Config::default(),
};
let params = build_params(&opts).unwrap();
assert!(params.is_some());
let params = params.unwrap();
assert_eq!(
params.fields,
Some(vec![
"name".to_string(),
"url".to_string(),
"abstract".to_string()
])
);
}
#[test]
fn test_build_params_with_limit() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: None,
filter: vec![],
limit: Some(100),
config: Config::default(),
};
let params = build_params(&opts).unwrap();
assert!(params.is_some());
let params = params.unwrap();
assert_eq!(params.limit, Some(100));
}
#[test]
fn test_build_params_with_filters() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: None,
filter: vec!["project=enwiki".to_string(), "language=en".to_string()],
limit: None,
config: Config::default(),
};
let params = build_params(&opts).unwrap();
assert!(params.is_some());
let params = params.unwrap();
assert!(params.filters.is_some());
let filters = params.filters.unwrap();
assert_eq!(filters.len(), 2);
}
#[test]
fn test_build_params_invalid_filter() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: None,
filter: vec!["invalid_filter".to_string()],
limit: None,
config: Config::default(),
};
let result = build_params(&opts);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Invalid filter format"));
}
#[test]
fn test_build_params_combined() {
let opts = GlobalOpts {
token: None,
output: OutputFormat::Json,
fields: Some("name".to_string()),
filter: vec!["project=enwiki".to_string()],
limit: Some(50),
config: Config::default(),
};
let params = build_params(&opts).unwrap();
assert!(params.is_some());
let params = params.unwrap();
assert!(params.fields.is_some());
assert!(params.filters.is_some());
assert_eq!(params.limit, Some(50));
}
}