Skip to content

Commit

Permalink
added tests; added to covplot [#2]
Browse files Browse the repository at this point in the history
  • Loading branch information
esteinig committed Mar 16, 2022
1 parent e17abd2 commit bffd130
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 28 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ include = [
anyhow = "1.0"
structopt = "0.3"
clap = "2.33.0"
rayon = "1.5.1"
thiserror = "1.0"
env_logger = "0.9.0"
log = "0.4.0"
float_eq = "0.6.1"
rust-lapper = "1.0.0"
noodles = { version = "0.20.0", features = ["fasta"] }
crossterm = "0.23.0"
itertools = "0.10.3"

[dev-dependencies]
assert_cmd = "2.0.1"
predicates = "1"
float_eq = "0.6.1"

[[bin]]
name = "vircov"
path = "src/main.rs"
40 changes: 30 additions & 10 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,49 @@ use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(name = "vircov")]
pub struct Cli {
/// Alignment in PAF format
/// Alignment file (PAF)
///
/// Alignment input file, currently supports PAF (minimap2)
#[structopt(
short = "p",
long = "paf",
parse(try_from_os_str = check_file_exists)
)]
pub paf: PathBuf,
pub path: PathBuf,
/// Reference sequences in FASTA format
///
/// If the input are alignments in PAF format, computation of the
/// total coverage against each target sequence requires the sequence
/// lengths extracted from the FASTA file used in the alignment.
#[structopt(
short = "f",
long = "fasta",
parse(try_from_os_str = check_file_exists)
)]
pub fasta: Option<PathBuf>,
/// Minimum lenmgth of the aligned query sequence
/// Minimum length of the aligned query sequence
///
/// Filters (&) alignments by minimum length of the aligned query sequence,
/// which corresponds to the difference between query alignment end and
/// start positions.
#[structopt(short = "l", long = "min-len", default_value = "50")]
pub min_len: u64,
/// Minimum coverage of the aligned query sequence
#[structopt(short = "c", long = "min-cov", default_value = "0.5")]
///
/// Filters (&) alignmentsby minimum proportion of the query sequence involved
/// in the alignment which corresponds to the division of the length of the
/// aligned query sequence by the length of the query sequence.
#[structopt(short = "c", long = "min-cov", default_value = "0")]
pub min_cov: f64,
/// Minimum mapping quality of the alignment
///
/// Filters (&) alignments by a minimum mapping quality.
#[structopt(short = "q", long = "min-mapq", default_value = "30")]
pub min_mapq: u8,
/// Verbose output statistics
///
/// Single flag (-v) adds whitespace separated tags in the last column,
/// corresponding to the number of inferred alignment coverage blocks.
/// Each tag specifies: start of block, end of block and number of
/// alignments in the block separated by a semicolon [example: 3450:3500:9]
/// Each tag contains: start of block, end of block and number of
/// alignments in the block, separated by semicolons (e.g.3450:3500:9)
#[structopt(short, long, parse(from_occurrences = parse_verbosity))]
pub verbose: u64
}
Expand Down Expand Up @@ -64,10 +78,16 @@ pub fn parse_verbosity(v: u64) -> u64 {
#[cfg(test)]
mod tests {
use super::*;

#[test]
#[should_panic]
fn file_check_not_exist() {
check_file_exists(&OsStr::new("tests/cases/no_bueno.paf")).unwrap();
}

#[test]
fn verbosity_exceeds_limit() {
let passed_args = vec!["vircov", "-vv", "--paf", "tests/cases/test_ok.paf"];
let passed_args = vec!["vircov", "-vv", "tests/cases/test_ok.paf"];
let args = Cli::from_iter_safe(passed_args);

let actual = args.unwrap().verbose;
Expand All @@ -79,7 +99,7 @@ mod tests {

#[test]
fn valid_verbosity_level() {
let passed_args = vec!["vircov", "-v", "--paf", "tests/cases/test_ok.paf"];
let passed_args = vec!["vircov", "-v", "tests/cases/test_ok.paf"];
let args = Cli::from_iter_safe(passed_args);

let actual = args.unwrap().verbose;
Expand Down
10 changes: 5 additions & 5 deletions src/covplot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ impl CovPlot {

// For each segment interval, use the merged target coverage regions to determine whether they are
// contained within the segment interval:
// 0 indicates it is not
// 1 indicates it is
// 0 indicates it is not contained
// 1 indicates it is contained
// 2 indicates a coundary between two merged target regions
let tagged_segments = segment_intervals.iter().map(|x| {
let _count = merged_targets.find(x.start, x.stop).count();
Expand All @@ -73,8 +73,8 @@ impl CovPlot {
}

// Prints the five prime end to console in default style
pub fn to_console(&self, seq_name: String, coverage_color: Color) -> Result<(), CovPlotError>{
println!("{}", seq_name);
pub fn to_console(&self, seq_name: String, seq_length: u64, coverage_color: Color) -> Result<(), CovPlotError>{
println!("{} - {} bp", seq_name, seq_length);
execute!(
stdout(),
Print("5'")
Expand All @@ -84,7 +84,7 @@ impl CovPlot {
0 => (Color::Reset, Attribute::Reset),
1 => (coverage_color, Attribute::Reset),
2 => (coverage_color, Attribute::Bold),
_ => (Color::Yellow, Attribute::Underlined)
_ => (Color::Yellow, Attribute::Bold)
};
execute!(
stdout(),
Expand Down
7 changes: 3 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use structopt::StructOpt;

use crate::cli::Cli;
use crate::paf::PafFile;
use crate::covplot::CovPlot;

mod cli;
mod paf;
Expand All @@ -13,13 +12,13 @@ mod covplot;
///
/// Run the application from arguments provided
/// by the command line interface
#[cfg(not(tarpaulin_include))]
fn main() -> Result<()> {
env_logger::init();

let args = Cli::from_args();

let paf = PafFile::from(
args.paf,
args.path,
args.fasta,
args.min_len,
args.min_cov,
Expand All @@ -28,6 +27,6 @@ fn main() -> Result<()> {

paf.target_coverage_distribution(args.verbose)?;
paf.target_coverage_plots(100)?;

Ok(())
}
13 changes: 8 additions & 5 deletions src/paf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ impl PafFile {

let covplot = CovPlot::new(targets, seq_length, max_width)?;

covplot.to_console(target_name, Color::Red)?;
covplot.to_console(target_name, seq_length, Color::Red)?;

}

Expand Down Expand Up @@ -311,13 +311,15 @@ mod tests {
struct TestCases {
// Valid PAF record struct instance
paf_test_record_ok: PafRecord,
// Valid PAF string with sufficient fields to parse
// Valid PAF string, sufficient fields to parse
paf_test_str_ok: String,
// Invalid PAF string with too few fields to parse
// Invalid PAF string, too few fields to parse
paf_test_str_size_fail: String,
// Path to file with valid PAF format where records are formatted correctly
// Valid PAF file
paf_test_file_ok: PathBuf,
// Path to file with invalid PAF format where record has too few fields
// Valid FASTA file
paf_test_fasta_ok: PathBuf,
// Invalid PAF format, record has too few fields
paf_test_file_record_size_fail: PathBuf,
}

Expand Down Expand Up @@ -345,6 +347,7 @@ mod tests {
"query\t4\t400\t404\t+\ttarget\t5\t500\t504\t4\t4",
),
paf_test_file_ok: PathBuf::from("tests/cases/test_ok.paf"),
paf_test_fasta_ok: PathBuf::from("tests/cases/test_ok.fasta"),
paf_test_file_record_size_fail: PathBuf::from(
"tests/cases/test_record_size_fail.paf",
),
Expand Down
29 changes: 29 additions & 0 deletions tests/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use assert_cmd::prelude::*;
use predicates::prelude::*;
use std::process::Command;

#[test]
fn input_file_doesnt_exist() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
cmd.args(vec!["file/doesnt/exist.paf"]);
cmd.assert()
.failure()
.stderr(predicate::str::contains("does not exist"));

Ok(())
}

#[test]
fn valid_inputs_raise_no_errors() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
cmd.args(vec![
"tests/cases/test_ok.paf",
"--fasta",
"tests/cases/test_ok.fasta",
"-v"
]);

cmd.assert().success();

Ok(())
}
File renamed without changes.

0 comments on commit bffd130

Please sign in to comment.