#![cfg(feature = "rcsb-async")]
use pdbrust::rcsb::{
AsyncDownloadOptions, FileFormat, download_multiple_async, download_pdb_string_async,
download_structure_async, download_to_file_async,
};
use tempfile::tempdir;
#[test]
fn test_async_options_default() {
let options = AsyncDownloadOptions::default();
assert_eq!(options.max_concurrent, 5);
assert_eq!(options.rate_limit_ms, 100);
assert_eq!(options.timeout_secs, 30);
assert_eq!(options.retries, 2);
}
#[test]
fn test_async_options_new() {
let options = AsyncDownloadOptions::new();
assert_eq!(options.max_concurrent, 5);
assert_eq!(options.rate_limit_ms, 100);
}
#[test]
fn test_async_options_conservative() {
let options = AsyncDownloadOptions::conservative();
assert_eq!(options.max_concurrent, 2);
assert_eq!(options.rate_limit_ms, 500);
assert_eq!(options.timeout_secs, 60);
assert_eq!(options.retries, 3);
}
#[test]
fn test_async_options_fast() {
let options = AsyncDownloadOptions::fast();
assert_eq!(options.max_concurrent, 20);
assert_eq!(options.rate_limit_ms, 25);
assert_eq!(options.timeout_secs, 30);
assert_eq!(options.retries, 1);
}
#[test]
fn test_async_options_builder_max_concurrent() {
let options = AsyncDownloadOptions::new().with_max_concurrent(10);
assert_eq!(options.max_concurrent, 10);
assert_eq!(options.rate_limit_ms, 100); }
#[test]
fn test_async_options_builder_rate_limit() {
let options = AsyncDownloadOptions::new().with_rate_limit_ms(50);
assert_eq!(options.rate_limit_ms, 50);
assert_eq!(options.max_concurrent, 5); }
#[test]
fn test_async_options_builder_timeout() {
let options = AsyncDownloadOptions::new().with_timeout_secs(60);
assert_eq!(options.timeout_secs, 60);
}
#[test]
fn test_async_options_builder_retries() {
let options = AsyncDownloadOptions::new().with_retries(5);
assert_eq!(options.retries, 5);
}
#[test]
fn test_async_options_builder_chained() {
let options = AsyncDownloadOptions::new()
.with_max_concurrent(10)
.with_rate_limit_ms(50)
.with_timeout_secs(45)
.with_retries(3);
assert_eq!(options.max_concurrent, 10);
assert_eq!(options.rate_limit_ms, 50);
assert_eq!(options.timeout_secs, 45);
assert_eq!(options.retries, 3);
}
#[test]
fn test_async_options_clone() {
let options = AsyncDownloadOptions::conservative();
let cloned = options.clone();
assert_eq!(cloned.max_concurrent, options.max_concurrent);
assert_eq!(cloned.rate_limit_ms, options.rate_limit_ms);
}
#[test]
fn test_async_options_debug() {
let options = AsyncDownloadOptions::default();
let debug = format!("{:?}", options);
assert!(debug.contains("max_concurrent"));
assert!(debug.contains("rate_limit_ms"));
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_pdb_string_async_pdb_format() {
let content = download_pdb_string_async("1UBQ", FileFormat::Pdb)
.await
.expect("Failed to download 1UBQ.pdb");
assert!(content.contains("HEADER"));
assert!(content.contains("ATOM"));
assert!(content.len() > 1000);
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_pdb_string_async_cif_format() {
let content = download_pdb_string_async("1UBQ", FileFormat::Cif)
.await
.expect("Failed to download 1UBQ.cif");
assert!(content.contains("_atom_site"));
assert!(content.len() > 1000);
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_structure_async_pdb_format() {
let structure = download_structure_async("1UBQ", FileFormat::Pdb)
.await
.expect("Failed to download and parse 1UBQ.pdb");
assert!(structure.atoms.len() > 500);
assert!(!structure.get_chain_ids().is_empty());
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_structure_async_cif_format() {
let structure = download_structure_async("1UBQ", FileFormat::Cif)
.await
.expect("Failed to download and parse 1UBQ.cif");
assert!(structure.atoms.len() > 500);
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_to_file_async() {
let dir = tempdir().expect("Failed to create temp dir");
let path = dir.path().join("1UBQ.pdb");
download_to_file_async("1UBQ", &path, FileFormat::Pdb)
.await
.expect("Failed to download 1UBQ to file");
assert!(path.exists());
let content = std::fs::read_to_string(&path).expect("Failed to read file");
assert!(content.contains("ATOM"));
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_async_nonexistent_pdb() {
let result = download_pdb_string_async("XXXX", FileFormat::Pdb).await;
assert!(result.is_err());
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_simple() {
let pdb_ids = vec!["1UBQ", "8HM2"];
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, None).await;
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, "1UBQ");
assert_eq!(results[1].0, "8HM2");
for (pdb_id, result) in &results {
assert!(
result.is_ok(),
"Failed to download {}: {:?}",
pdb_id,
result
);
let structure = result.as_ref().unwrap();
assert!(structure.atoms.len() > 100, "{} has too few atoms", pdb_id);
}
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_with_options() {
let pdb_ids = vec!["1UBQ", "4INS"];
let options = AsyncDownloadOptions::conservative();
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, Some(options)).await;
assert_eq!(results.len(), 2);
for (pdb_id, result) in &results {
assert!(result.is_ok(), "Failed to download {}", pdb_id);
}
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_partial_failure() {
let pdb_ids = vec!["1UBQ", "XXXX", "8HM2"];
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, None).await;
assert_eq!(results.len(), 3);
assert!(results[0].1.is_ok());
assert!(results[1].1.is_err());
assert!(results[2].1.is_ok());
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_larger_batch() {
let pdb_ids = vec!["1UBQ", "8HM2", "4INS", "1HHB", "2MBP"];
let options = AsyncDownloadOptions::default().with_max_concurrent(3);
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, Some(options)).await;
assert_eq!(results.len(), 5);
let successful: Vec<_> = results.iter().filter(|(_, r)| r.is_ok()).collect();
assert!(
successful.len() >= 4,
"Only {} of 5 downloads succeeded",
successful.len()
);
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_cif_format() {
let pdb_ids = vec!["1UBQ", "8HM2"];
let results = download_multiple_async(&pdb_ids, FileFormat::Cif, None).await;
assert_eq!(results.len(), 2);
for (pdb_id, result) in &results {
assert!(result.is_ok(), "Failed to download {} as CIF", pdb_id);
}
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_empty_list() {
let pdb_ids: Vec<&str> = vec![];
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, None).await;
assert!(results.is_empty());
}
#[tokio::test]
#[ignore = "requires network access"]
async fn test_download_multiple_async_single_item() {
let pdb_ids = vec!["1UBQ"];
let results = download_multiple_async(&pdb_ids, FileFormat::Pdb, None).await;
assert_eq!(results.len(), 1);
assert!(results[0].1.is_ok());
}