use anyhow::Result;
use assert_cmd::cargo;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
use xsra::cli::{
AccessionOptions, DumpOutput, FilterOptions, InputOptions, OutputFormat, Provider,
};
use xsra::dump::dump;
use xsra::output::Compression;
mod fixtures;
use fixtures::setup::TestFixtures;
fn default_accession_options() -> AccessionOptions {
AccessionOptions {
full_quality: false,
lite_only: false,
provider: Provider::Https,
retry_limit: 5,
retry_delay: 500,
gcp_project_id: None,
}
}
#[test]
fn test_simple_fastq_dump_cli() -> Result<()> {
let fixtures = TestFixtures::ensure_fixtures()?;
let mut cmd = cargo::cargo_bin_cmd!("xsra");
cmd.arg("dump")
.arg(fixtures.small_variable_sra)
.arg("--limit")
.arg("10");
cmd.assert()
.success()
.stdout(predicate::str::starts_with("@"))
.stdout(predicate::str::contains("\n+\n"))
.stdout(predicate::str::ends_with("\n"));
let output = cmd.output()?;
let stdout = String::from_utf8(output.stdout)?;
assert_eq!(
stdout.lines().count(),
40,
"Expected 10 records * 4 lines/record"
);
Ok(())
}
#[test]
fn test_split_file_dump() -> Result<()> {
let fixtures = TestFixtures::ensure_fixtures()?;
let temp_dir = TempDir::new()?;
let input = InputOptions {
accession: fixtures.small_variable_sra.clone(),
options: default_accession_options(),
};
let output = DumpOutput {
outdir: temp_dir.path().to_string_lossy().to_string(),
prefix: "test".to_string(),
compression: Compression::Uncompressed,
format: OutputFormat::Fastq,
named_pipes: false,
split: true,
keep_empty: false,
include_sid: false,
};
let filter_opts = FilterOptions {
include: vec![],
skip_technical: false,
min_read_len: 1,
limit: Some(100), };
let result = dump(&input, 1, &output, filter_opts);
assert!(
result.is_ok(),
"Split dump command failed: {:?}",
result.err()
);
let mut split_files_found = 0;
for entry in fs::read_dir(temp_dir.path())? {
let entry = entry?;
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.starts_with("test") && file_name.ends_with(".fq") {
split_files_found += 1;
let file_size = fs::metadata(entry.path())?.len();
assert!(file_size > 0, "Split file {} is empty", file_name);
}
}
assert!(split_files_found > 0, "No split files were created");
Ok(())
}
#[test]
fn test_filtered_dump_cli() -> Result<()> {
let fixtures = TestFixtures::ensure_fixtures()?;
let mut cmd = cargo::cargo_bin_cmd!("xsra");
cmd.arg("dump")
.arg(fixtures.small_variable_sra)
.arg("--skip-technical")
.arg("--min-read-len")
.arg("50")
.arg("--limit")
.arg("10")
.arg("--include")
.arg("0,1");
cmd.assert()
.success()
.stdout(predicate::str::starts_with("@"));
Ok(())
}
#[test]
fn test_empty_file_removal() -> Result<()> {
let fixtures = TestFixtures::ensure_fixtures()?;
let temp_dir = TempDir::new()?;
let input = InputOptions {
accession: fixtures.small_variable_sra.clone(),
options: default_accession_options(),
};
let output = DumpOutput {
outdir: temp_dir.path().to_string_lossy().to_string(),
prefix: "test".to_string(),
compression: Compression::Uncompressed,
format: OutputFormat::Fastq,
named_pipes: false,
split: true,
keep_empty: false,
include_sid: false,
};
let filter_opts = FilterOptions {
include: vec![0], skip_technical: true,
min_read_len: 10000, limit: Some(50), };
let result = dump(&input, 1, &output, filter_opts);
assert!(
result.is_ok(),
"Empty file removal test failed: {:?}",
result.err()
);
let mut file_count = 0;
for entry in fs::read_dir(temp_dir.path())? {
let entry = entry?;
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.starts_with("test") {
file_count += 1;
}
}
assert!(file_count >= 0, "File count should be non-negative");
Ok(())
}
#[test]
#[cfg(unix)]
fn test_named_pipes_io() -> Result<()> {
use std::os::unix::fs::FileTypeExt;
use tempfile::TempDir;
let temp_dir = TempDir::new()?;
let test_fifo = temp_dir.path().join("test.fq");
let status = std::process::Command::new("mkfifo")
.arg(&test_fifo)
.status()?;
assert!(status.success(), "mkfifo command failed");
assert!(test_fifo.exists(), "FIFO was not created");
let metadata = std::fs::metadata(&test_fifo)?;
assert!(metadata.file_type().is_fifo(), "Created file is not a FIFO");
Ok(())
}
#[test]
fn test_fasta_output_cli() -> Result<()> {
let fixtures = TestFixtures::ensure_fixtures()?;
let mut cmd = cargo::cargo_bin_cmd!("xsra");
cmd.arg("dump")
.arg(fixtures.small_variable_sra)
.arg("--format")
.arg("a")
.arg("--limit")
.arg("10");
cmd.assert()
.success()
.stdout(predicate::str::starts_with(">"));
let output = cmd.output()?;
let stdout = String::from_utf8(output.stdout)?;
assert_eq!(
stdout.lines().count(),
20,
"Expected 10 records * 2 lines/record"
);
Ok(())
}