use assert_cmd::prelude::*; use lazy_static::lazy_static; use predicates::{ boolean::NotPredicate, str::{contains, is_empty, is_match, PredicateStrExt}, }; use regex::Regex; use std::process::Command; lazy_static! { static ref FF_FR_AF_REGEX: Regex = Regex::new("FF_FR_AF=(.+?),(.+?)\t").unwrap(); } fn extract_filters(output: &[u8]) -> Vec { String::from_utf8(output.to_vec()) .unwrap() .lines() .filter(|l| !l.starts_with('#')) .flat_map(|l| l.split('\t').nth(6)) .map(String::from) .collect() } #[test] fn cli_no_args() { Command::cargo_bin("rustynuc").unwrap().assert().failure(); } #[test] fn cli_no_such_file() { Command::cargo_bin("rustynuc") .unwrap() .args(&["tests/no_such_file.bam"]) .assert() .failure() .stderr(contains("FileNotFound").trim()); } #[test] fn cli_normal_bam() { Command::cargo_bin("rustynuc") .unwrap() .args(&["-r", "tests/input/ref.fa.gz", "tests/input/normal.bam"]) .assert() .stdout(is_empty()); } #[test] fn cli_oxog_bam() { Command::cargo_bin("rustynuc") .unwrap() .args(&["-r", "tests/input/ref.fa.gz", "tests/input/oxog.bam"]) .assert() .stdout(contains("NC_009617.1_C_3963_3964")); } #[test] fn cli_warn_about_mnp() { Command::cargo_bin("rustynuc") .unwrap() .args(&[ "-r", "tests/input/ref.fa.gz", "-b", "tests/input/oxog.vcf.gz", "tests/input/oxog.bam", ]) .assert() .stderr(contains("Identified MNP at record")); } #[test] fn cli_dont_warn_as_no_mnp() { let should_not_contain_mnp = NotPredicate::new(contains("Identified MNP at record")); Command::cargo_bin("rustynuc") .unwrap() .args(&[ "-r", "tests/input/ref.fa.gz", "-b", "tests/input/oxog.vcf.onlysnp.gz", "tests/input/oxog.bam", ]) .assert() .stderr(should_not_contain_mnp); } #[test] fn cli_oxog_bcf() { let expected = vec!["PASS", "FishersOxoG;AfTooLow", "FishersOxoG;AfTooLow"]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "-r", "tests/input/ref.fa.gz", "-b", "tests/input/oxog.vcf.gz", "tests/input/oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected); } #[test] fn cli_oxog_bcf_skip_fishers() { let expected = vec!["PASS", "AfTooLow", "AfTooLow"]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--skip-fishers", "-r", "tests/input/ref.fa.gz", "-b", "tests/input/oxog.vcf.gz", "tests/input/oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected); } #[test] fn cli_print_all() { Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--all", "-r", "tests/input/ref.fa.gz", "tests/input/oxog.bam", ]) .assert() .stdout(is_match(r#"NC_009617.1\s1284\s1285"#).unwrap()); } #[test] fn cli_af_not_above_one() { let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--all", "-r", "tests/input/high_af/high_af.oxog.ref.fa.gz", "-b", "tests/input/high_af/high_af.oxog.vcf.gz", "tests/input/high_af/high_af.oxog.bam", ]) .unwrap() .stdout; if let Some(captures) = FF_FR_AF_REGEX.captures(&String::from_utf8(output).unwrap()) { assert!(captures.len() == 3); assert!(captures.get(1).unwrap().as_str().parse::().unwrap() < 1.0); assert!(captures.get(2).unwrap().as_str().parse::().unwrap() < 1.0); } else { panic!("No FF_FR_AF in output") } } #[test] fn cli_not_oxog_as_above_either_pass() { let expected = vec!["PASS".to_string()]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "-r", "tests/input/high_af/high_af.oxog.ref.fa.gz", "-b", "tests/input/high_af/high_af.oxog.vcf.gz", "tests/input/high_af/high_af.oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected) } #[test] fn cli_not_false_positive_as_they_pass_either_above_af() { let expected = vec!["PASS".to_string()]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--af-both-pass", "0.6", "-r", "tests/input/high_af/high_af.oxog.ref.fa.gz", "-b", "tests/input/high_af/high_af.oxog.vcf.gz", "tests/input/high_af/high_af.oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected) } #[test] fn cli_not_false_positive_oxog_one_freq_above_af_either_pass() { let expected = vec!["PASS".to_string()]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--af-either-pass", "0.6", "-r", "tests/input/high_af/high_af.oxog.ref.fa.gz", "-b", "tests/input/high_af/high_af.oxog.vcf.gz", "tests/input/high_af/high_af.oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected); } #[test] fn cli_false_positive_oxog_as_not_above_either_or_both() { let expected = vec!["FishersOxoG".to_string()]; let output = Command::cargo_bin("rustynuc") .unwrap() .args(&[ "--af-both-pass", "0.6", "--af-either-pass", "0.8", "-r", "tests/input/high_af/high_af.oxog.ref.fa.gz", "-b", "tests/input/high_af/high_af.oxog.vcf.gz", "tests/input/high_af/high_af.oxog.bam", ]) .unwrap() .stdout; let filter_result = extract_filters(&output); assert_eq!(filter_result, expected); }