use std::collections::HashMap;
use crate::{
composition::ByteIndexCounts,
data::{
alphas::*,
mappings::{validator::ByteValidator, *},
nucleotides::CodonExtension,
},
prelude::Nucleotides,
};
#[test]
fn gc_self_test() {
#[rustfmt::skip]
let gc = [
(b"TAA", b'*'), (b"TAG", b'*'), (b"TAR", b'*'), (b"TGA", b'*'), (b"TRA", b'*'), (b"GCA", b'A'), (b"GCB", b'A'), (b"GCC", b'A'), (b"GCD", b'A'), (b"GCG", b'A'), (b"GCH", b'A'),
(b"GCK", b'A'), (b"GCM", b'A'), (b"GCN", b'A'), (b"GCR", b'A'), (b"GCS", b'A'), (b"GCT", b'A'), (b"GCV", b'A'), (b"GCW", b'A'), (b"GCY", b'A'), (b"TGC", b'C'), (b"TGT", b'C'),
(b"TGY", b'C'), (b"GAC", b'D'), (b"GAT", b'D'), (b"GAY", b'D'), (b"GAA", b'E'), (b"GAG", b'E'), (b"GAR", b'E'), (b"TTC", b'F'), (b"TTT", b'F'), (b"TTY", b'F'), (b"GGA", b'G'),
(b"GGB", b'G'), (b"GGC", b'G'), (b"GGD", b'G'), (b"GGG", b'G'), (b"GGH", b'G'), (b"GGK", b'G'), (b"GGM", b'G'), (b"GGN", b'G'), (b"GGR", b'G'), (b"GGS", b'G'), (b"GGT", b'G'),
(b"GGV", b'G'), (b"GGW", b'G'), (b"GGY", b'G'), (b"CAC", b'H'), (b"CAT", b'H'), (b"CAY", b'H'), (b"ATA", b'I'), (b"ATC", b'I'), (b"ATH", b'I'), (b"ATM", b'I'), (b"ATT", b'I'),
(b"ATW", b'I'), (b"ATY", b'I'), (b"AAA", b'K'), (b"AAG", b'K'), (b"AAR", b'K'), (b"CTA", b'L'), (b"CTB", b'L'), (b"CTC", b'L'), (b"CTD", b'L'), (b"CTG", b'L'), (b"CTH", b'L'),
(b"CTK", b'L'), (b"CTM", b'L'), (b"CTN", b'L'), (b"CTR", b'L'), (b"CTS", b'L'), (b"CTT", b'L'), (b"CTV", b'L'), (b"CTW", b'L'), (b"CTY", b'L'), (b"TTA", b'L'), (b"TTG", b'L'),
(b"TTR", b'L'), (b"YTA", b'L'), (b"YTG", b'L'), (b"YTR", b'L'), (b"ATG", b'M'), (b"AAC", b'N'), (b"AAT", b'N'), (b"AAY", b'N'), (b"CCA", b'P'), (b"CCB", b'P'), (b"CCC", b'P'),
(b"CCD", b'P'), (b"CCG", b'P'), (b"CCH", b'P'), (b"CCK", b'P'), (b"CCM", b'P'), (b"CCN", b'P'), (b"CCR", b'P'), (b"CCS", b'P'), (b"CCT", b'P'), (b"CCV", b'P'), (b"CCW", b'P'),
(b"CCY", b'P'), (b"CAA", b'Q'), (b"CAG", b'Q'), (b"CAR", b'Q'), (b"AGA", b'R'), (b"AGG", b'R'), (b"AGR", b'R'), (b"CGA", b'R'), (b"CGB", b'R'), (b"CGC", b'R'), (b"CGD", b'R'),
(b"CGG", b'R'), (b"CGH", b'R'), (b"CGK", b'R'), (b"CGM", b'R'), (b"CGN", b'R'), (b"CGR", b'R'), (b"CGS", b'R'), (b"CGT", b'R'), (b"CGV", b'R'), (b"CGW", b'R'), (b"CGY", b'R'),
(b"MGA", b'R'), (b"MGG", b'R'), (b"MGR", b'R'), (b"AGC", b'S'), (b"AGT", b'S'), (b"AGY", b'S'), (b"TCA", b'S'), (b"TCB", b'S'), (b"TCC", b'S'), (b"TCD", b'S'), (b"TCG", b'S'),
(b"TCH", b'S'), (b"TCK", b'S'), (b"TCM", b'S'), (b"TCN", b'S'), (b"TCR", b'S'), (b"TCS", b'S'), (b"TCT", b'S'), (b"TCV", b'S'), (b"TCW", b'S'), (b"TCY", b'S'), (b"ACA", b'T'),
(b"ACB", b'T'), (b"ACC", b'T'), (b"ACD", b'T'), (b"ACG", b'T'), (b"ACH", b'T'), (b"ACK", b'T'), (b"ACM", b'T'), (b"ACN", b'T'), (b"ACR", b'T'), (b"ACS", b'T'), (b"ACT", b'T'),
(b"ACV", b'T'), (b"ACW", b'T'), (b"ACY", b'T'), (b"GTA", b'V'), (b"GTB", b'V'), (b"GTC", b'V'), (b"GTD", b'V'), (b"GTG", b'V'), (b"GTH", b'V'), (b"GTK", b'V'), (b"GTM", b'V'),
(b"GTN", b'V'), (b"GTR", b'V'), (b"GTS", b'V'), (b"GTT", b'V'), (b"GTV", b'V'), (b"GTW", b'V'), (b"GTY", b'V'), (b"TGG", b'W'), (b"TAC", b'Y'), (b"TAT", b'Y'), (b"TAY", b'Y'),
(b"...", b'.'), (b"---", b'-'), (b"NNN", b'X'),
(b"UAA", b'*'), (b"UAG", b'*'), (b"UAR", b'*'), (b"UGA", b'*'), (b"URA", b'*'), (b"GCU", b'A'), (b"UGC", b'C'), (b"UGU", b'C'), (b"UGY", b'C'), (b"GAU", b'D'), (b"UUC", b'F'),
(b"UUU", b'F'), (b"UUY", b'F'), (b"GGU", b'G'), (b"CAU", b'H'), (b"AUA", b'I'), (b"AUC", b'I'), (b"AUH", b'I'), (b"AUM", b'I'), (b"AUU", b'I'), (b"AUW", b'I'), (b"AUY", b'I'),
(b"CUA", b'L'), (b"CUB", b'L'), (b"CUC", b'L'), (b"CUD", b'L'), (b"CUG", b'L'), (b"CUH", b'L'), (b"CUK", b'L'), (b"CUM", b'L'), (b"CUN", b'L'), (b"CUR", b'L'), (b"CUS", b'L'),
(b"CUU", b'L'), (b"CUV", b'L'), (b"CUW", b'L'), (b"CUY", b'L'), (b"UUA", b'L'), (b"UUG", b'L'), (b"UUR", b'L'), (b"YUA", b'L'), (b"YUG", b'L'), (b"YUR", b'L'), (b"AUG", b'M'),
(b"AAU", b'N'), (b"CCU", b'P'), (b"CGU", b'R'), (b"AGU", b'S'), (b"UCA", b'S'), (b"UCB", b'S'), (b"UCC", b'S'), (b"UCD", b'S'), (b"UCG", b'S'), (b"UCH", b'S'), (b"UCK", b'S'),
(b"UCM", b'S'), (b"UCN", b'S'), (b"UCR", b'S'), (b"UCS", b'S'), (b"UCU", b'S'), (b"UCV", b'S'), (b"UCW", b'S'), (b"UCY", b'S'), (b"ACU", b'T'), (b"GUA", b'V'), (b"GUB", b'V'),
(b"GUC", b'V'), (b"GUD", b'V'), (b"GUG", b'V'), (b"GUH", b'V'), (b"GUK", b'V'), (b"GUM", b'V'), (b"GUN", b'V'), (b"GUR", b'V'), (b"GUS", b'V'), (b"GUU", b'V'), (b"GUV", b'V'),
(b"GUW", b'V'), (b"GUY", b'V'), (b"UGG", b'W'), (b"UAC", b'Y'), (b"UAU", b'Y'), (b"UAY", b'Y')
];
for (codon, aa) in gc {
assert_eq!(aa, StdGeneticCode::get(codon).unwrap());
assert_eq!(aa, StdGeneticCode::translate_codon(codon));
assert_eq!(aa == b'*', StdGeneticCode::is_stop_codon(codon));
}
}
#[test]
fn test_dna_map() {
for i in 0..=255 {
match i {
b'A' | b'a' => assert_eq!(DNA_PROFILE_MAP.to_index(i), 0),
b'C' | b'c' => assert_eq!(DNA_PROFILE_MAP.to_index(i), 1),
b'G' | b'g' => assert_eq!(DNA_PROFILE_MAP.to_index(i), 2),
b'T' | b't' | b'U' | b'u' => assert_eq!(DNA_PROFILE_MAP.to_index(i), 3),
_ => assert_eq!(DNA_PROFILE_MAP.to_index(i), 4),
}
}
}
#[test]
fn test_dna_map_ignores_case() {
const MAP1: ByteIndexMap<5> = ByteIndexMap::new_ignoring_case(*b"acgtn", b'N').add_synonym_ignore_case(b'u', b'T');
const MAP2: ByteIndexMap<5> = ByteIndexMap::new_ignoring_case(*b"AcGtN", b'n').add_synonym_ignore_case(b'U', b't');
assert_eq!(DNA_PROFILE_MAP, MAP1);
assert_eq!(DNA_PROFILE_MAP, MAP2);
}
#[test]
fn test_def_a_map() {
const DEF_A_MAP: ByteIndexMap<4> = ByteIndexMap::new_ignoring_case(*b"ACGT", b'A').add_synonym_ignore_case(b'U', b'T');
for i in 0..=255 {
match i {
b'C' | b'c' => assert_eq!(DEF_A_MAP.to_index(i), 1),
b'G' | b'g' => assert_eq!(DEF_A_MAP.to_index(i), 2),
b'T' | b't' | b'U' | b'u' => assert_eq!(DEF_A_MAP.to_index(i), 3),
_ => assert_eq!(DEF_A_MAP.to_index(i), 0),
}
}
}
#[test]
fn test_case_sensitive() {
const DNA_MAP: ByteIndexMap<10> = ByteIndexMap::new(*b"ACGTNacgtn", b'N')
.add_synonym(b'U', b'T')
.add_synonym(b'u', b't');
for i in 0..=255 {
match i {
b'A' => assert_eq!(DNA_MAP.to_index(i), 0),
b'C' => assert_eq!(DNA_MAP.to_index(i), 1),
b'G' => assert_eq!(DNA_MAP.to_index(i), 2),
b'T' | b'U' => assert_eq!(DNA_MAP.to_index(i), 3),
b'a' => assert_eq!(DNA_MAP.to_index(i), 5),
b'c' => assert_eq!(DNA_MAP.to_index(i), 6),
b'g' => assert_eq!(DNA_MAP.to_index(i), 7),
b't' | b'u' => assert_eq!(DNA_MAP.to_index(i), 8),
b'n' => assert_eq!(DNA_MAP.to_index(i), 9),
_ => assert_eq!(DNA_MAP.to_index(i), 4),
}
}
}
#[test]
#[should_panic = "Attempted to map a byte multiple times in the same call!"]
fn test_duplicate() {
let _ = ByteIndexMap::new(*b"ACGTNA", b'N');
}
#[test]
#[should_panic = "Attempted to map a byte multiple times in the same call!"]
fn test_duplicate_nocase() {
let _ = ByteIndexMap::new_ignoring_case(*b"ACGTNA", b'N');
}
#[test]
#[should_panic = "The catch_all must be present in the byte_keys."]
fn test_missing_catch_all() {
let _ = ByteIndexMap::new(*b"ACGT", b'N');
}
#[test]
#[should_panic = "The catch_all must be present in the byte_keys."]
fn test_missing_catch_all_nocase() {
let _ = ByteIndexMap::new_ignoring_case(*b"ACGT", b'N');
}
const VALIDATOR_PAIRS: &[(&[u8], ByteValidator)] = &[
(DNA_IUPAC, IS_DNA_IUPAC_NO_GAPS),
(DNA_IUPAC_UC, IS_DNA_IUPAC_NO_GAPS_UC),
(b"acgturyswkmbdhvnACGTURYSWKMBDHVN-.", IS_DNA_IUPAC_WITH_GAPS),
(b"ACGTURYSWKMBDHVN-.", IS_DNA_IUPAC_WITH_GAPS_UC),
(DNA_ACGTN, IS_DNA_ACGTN_NO_GAPS),
(DNA_ACGTN_UC, IS_DNA_ACGTN_NO_GAPS_UC),
(b"ACGTN-", IS_DNA_ACGTN_STD_GAPS_UC),
(b"acgtACGT", IS_DNA_ACGT_NO_GAPS),
(b"ACGT", IS_DNA_ACGT_NO_GAPS_UC),
];
#[test]
fn test_alphabet_validators() {
for (alphabet, validator) in VALIDATOR_PAIRS {
for c in u8::MIN..=u8::MAX {
assert_eq!(alphabet.contains(&c), validator[c]);
}
}
}
const RETAIN_DNA_PAIRS: [(&[u8], ByteMap); 4] = [
(DNA_IUPAC, RETAIN_DNA_IUPAC_NO_GAPS_UC),
(b"acgturyswkmbdhvnACGTURYSWKMBDHVN-.", RETAIN_DNA_IUPAC_WITH_GAPS_UC),
(DNA_ACGTN, RETAIN_DNA_ACGTN_NO_GAPS_UC),
(b"acgtnACGTN-.", RETAIN_DNA_ACGTN_WITH_GAPS_UC),
];
#[test]
fn test_retain_dna() {
for (alphabet, converter) in RETAIN_DNA_PAIRS {
for c in u8::MIN..=u8::MAX {
let in_alphabet = alphabet.contains(&c);
if matches!(c, b'u' | b'U') {
assert_eq!(converter[c], b'T');
} else if in_alphabet {
if c.is_ascii_lowercase() {
assert_eq!(converter[c], c.to_ascii_uppercase());
} else {
assert_eq!(converter[c], c);
}
} else {
assert_eq!(converter[c], 0);
}
}
}
}
#[test]
fn test_retain_dna_iupac_correct_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b':' | b'~') {
assert_eq!(RETAIN_DNA_IUPAC_CORRECT_GAPS_UC[c], b'-');
} else {
assert_eq!(RETAIN_DNA_IUPAC_CORRECT_GAPS_UC[c], RETAIN_DNA_IUPAC_WITH_GAPS_UC[c]);
}
}
}
#[test]
fn test_retain_dna_acgt_no_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'n' | b'N') {
assert_eq!(RETAIN_DNA_ACGT_NO_GAPS_UC[c], 0);
} else {
assert_eq!(RETAIN_DNA_ACGT_NO_GAPS_UC[c], RETAIN_DNA_ACGTN_NO_GAPS_UC[c]);
}
}
}
#[test]
fn test_retain_dna_acgtn_std_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'.' | b':' | b'~') {
assert_eq!(RETAIN_DNA_ACGTN_STD_GAPS_UC[c], b'-');
} else {
assert_eq!(RETAIN_DNA_ACGTN_STD_GAPS_UC[c], RETAIN_DNA_ACGTN_WITH_GAPS_UC[c]);
}
}
}
#[test]
fn test_iupac_to_dna_acgtn_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'u' | b'U') {
assert_eq!(IUPAC_TO_DNA_ACGTN_UC[c], b'T');
} else if DNA_ACGTN.contains(&c) {
assert_eq!(IUPAC_TO_DNA_ACGTN_UC[c], c.to_ascii_uppercase());
} else if DNA_IUPAC.contains(&c) {
assert_eq!(IUPAC_TO_DNA_ACGTN_UC[c], b'N');
} else {
assert_eq!(IUPAC_TO_DNA_ACGTN_UC[c], c);
}
}
}
#[test]
fn test_iupac_to_dna_acgtn() {
for c in u8::MIN..=u8::MAX {
if c == b'u' {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], b't');
} else if c == b'U' {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], b'T');
} else if DNA_ACGTN.contains(&c) {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], c);
} else if DNA_IUPAC.contains(&c) {
if c.is_ascii_lowercase() {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], b'n');
} else {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], b'N');
}
} else {
assert_eq!(IUPAC_TO_DNA_ACGTN[c], c);
}
}
}
#[test]
fn test_recode_to_dna_acgtn_no_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'u' | b'U') {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS_UC[c], b'T');
} else if DNA_ACGTN.contains(&c) {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS_UC[c], c.to_ascii_uppercase());
} else {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS_UC[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_acgtn_with_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'u' | b'U') {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS_UC[c], b'T');
} else if DNA_ACGTN.contains(&c) {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS_UC[c], c.to_ascii_uppercase());
} else if matches!(c, b'-' | b'.') {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS_UC[c], c);
} else {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS_UC[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_acgtn_no_gaps() {
for c in u8::MIN..=u8::MAX {
if c == b'u' {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS[c], b't');
} else if c == b'U' {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS[c], b'T');
} else if DNA_ACGTN.contains(&c) {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS[c], c);
} else {
assert_eq!(RECODE_TO_DNA_ACGTN_NO_GAPS_UC[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_acgtn_with_gaps() {
for c in u8::MIN..=u8::MAX {
if c == b'u' {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS[c], b't');
} else if c == b'U' {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS[c], b'T');
} else if DNA_ACGTN.contains(&c) || matches!(c, b'-' | b'.') {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS[c], c);
} else {
assert_eq!(RECODE_TO_DNA_ACGTN_WITH_GAPS[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_iupac_no_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'u' | b'U') {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS_UC[c], b'T');
} else if DNA_IUPAC.contains(&c) {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS_UC[c], c.to_ascii_uppercase());
} else {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS_UC[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_iupac_with_gaps_uc() {
for c in u8::MIN..=u8::MAX {
if matches!(c, b'u' | b'U') {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS_UC[c], b'T');
} else if b"acgturyswkmbdhvnACGTURYSWKMBDHVN-.".contains(&c) {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS_UC[c], c.to_ascii_uppercase());
} else {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS_UC[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_iupac_no_gaps() {
for c in u8::MIN..=u8::MAX {
if c == b'u' {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS[c], b't');
} else if c == b'U' {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS[c], b'T');
} else if DNA_IUPAC.contains(&c) {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS[c], c);
} else {
assert_eq!(RECODE_TO_DNA_IUPAC_NO_GAPS[c], b'N');
}
}
}
#[test]
fn test_recode_to_dna_iupac_with_gaps() {
for c in u8::MIN..=u8::MAX {
if c == b'u' {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS[c], b't');
} else if c == b'U' {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS[c], b'T');
} else if b"acgturyswkmbdhvnACGTURYSWKMBDHVN-.".contains(&c) {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS[c], c);
} else {
assert_eq!(RECODE_TO_DNA_IUPAC_WITH_GAPS[c], b'N');
}
}
}
#[test]
fn test_to_rna() {
for c in u8::MIN..=u8::MAX {
if b"acgunACGUN".contains(&c) {
assert_eq!(TO_RNA[c], c);
} else if c == b't' {
assert_eq!(TO_RNA[c], b'u');
} else if c == b'T' {
assert_eq!(TO_RNA[c], b'U');
} else {
assert_eq!(TO_RNA[c], b'N');
}
}
}
#[test]
fn test_to_rna_uc() {
for c in u8::MIN..=u8::MAX {
assert_eq!(TO_RNA_UC[c], TO_RNA[c].to_ascii_uppercase());
}
}
#[test]
fn test_dna_profile_byte_index_counts() {
let seq = Nucleotides::from(b"TGCTCCACGNGCAGGCGCCTGN");
let mut counts = ByteIndexCounts::<usize, 5>::new(&DNA_PROFILE_MAP);
counts.tally_from_seq(seq);
assert_eq!(counts.into_inner(), [2, 8, 7, 3, 2]);
assert_eq!(counts.get_count(b'A'), 2);
assert_eq!(counts.get_count(b'C'), 8);
assert_eq!(counts.get_count(b'G'), 7);
assert_eq!(counts.get_count(b'T'), 3);
assert_eq!(counts.get_count(b'N'), 2);
counts += b'A';
counts += b'C';
assert_eq!(counts.into_inner(), [3, 9, 7, 3, 2]);
assert_eq!(counts.get_count(b'A'), 3);
assert_eq!(counts.get_count(b'C'), 9);
assert_eq!(counts.get_count(b'G'), 7);
assert_eq!(counts.get_count(b'T'), 3);
assert_eq!(counts.get_count(b'N'), 2);
}
#[test]
fn test_unambig_dna_profile_byte_index_counts() {
let seq = Nucleotides::from(b"TGCTCCACGNGCAGGCGCCTGN");
let mut counts = ByteIndexCounts::<usize, 4>::new(&DNA_UNAMBIG_PROFILE_MAP);
counts.tally_from_seq(seq);
assert_eq!(counts.into_inner(), [4, 8, 7, 3]);
assert_eq!(counts.get_count(b'A'), 4);
assert_eq!(counts.get_count(b'C'), 8);
assert_eq!(counts.get_count(b'G'), 7);
assert_eq!(counts.get_count(b'T'), 3);
counts += b'A';
counts += b'C';
assert_eq!(counts.into_inner(), [5, 9, 7, 3]);
assert_eq!(counts.get_count(b'A'), 5);
assert_eq!(counts.get_count(b'C'), 9);
assert_eq!(counts.get_count(b'G'), 7);
assert_eq!(counts.get_count(b'T'), 3);
}
#[test]
fn test_alphabet_range() {
const MAP1: ByteMap = ByteMap::all(0).preserve_range(b'A'..=b'Z');
const MAP2: ByteMap = MAP1.preserve_range(b'a'..=b'z');
const MAP3: ByteMap = MAP2.map_range(b'a'..=b'z', b'A'..=b'Z');
const MAP4: ByteMap = ByteMap::identity().map_range_to_one(b'a'..=b'z', 0);
for byte in u8::MIN..=u8::MAX {
if byte.is_ascii_uppercase() {
assert_eq!(MAP1[byte], byte);
assert_eq!(MAP2[byte], byte);
assert_eq!(MAP3[byte], byte);
assert_eq!(MAP4[byte], byte);
} else if byte.is_ascii_lowercase() {
assert_eq!(MAP1[byte], 0);
assert_eq!(MAP2[byte], byte);
assert_eq!(MAP3[byte], byte.to_ascii_uppercase());
assert_eq!(MAP4[byte], 0);
} else {
assert_eq!(MAP1[byte], 0);
assert_eq!(MAP2[byte], 0);
assert_eq!(MAP3[byte], 0);
assert_eq!(MAP4[byte], byte);
}
}
}
#[test]
fn test_full_range() {
const MAP1: ByteMap = ByteMap::all(0).map_range(0..=255, 0..=255);
const MAP2: ByteMap = ByteMap::all(0).preserve_range(0..=255);
const MAP3: ByteMap = ByteMap::identity().map_range_to_one(0..=255, 0);
assert_eq!(MAP1, ByteMap::identity());
assert_eq!(MAP2, ByteMap::identity());
assert_eq!(MAP3, ByteMap::all(0));
}
#[test]
#[allow(clippy::reversed_empty_ranges)]
fn test_empty_range() {
const MAP1: ByteMap = ByteMap::all(0).map_range(10..=1, 255..=0);
const MAP2: ByteMap = ByteMap::all(0).preserve_range(255..=0);
const MAP3: ByteMap = ByteMap::identity().map_range_to_one(255..=0, 0);
assert_eq!(MAP1, ByteMap::all(0));
assert_eq!(MAP2, ByteMap::all(0));
assert_eq!(MAP3, ByteMap::identity());
}
fn ambig_residues() -> HashMap<u8, &'static [u8]> {
let mut out: HashMap<u8, &[u8]> = HashMap::new();
out.insert(b'A', b"A");
out.insert(b'C', b"C");
out.insert(b'G', b"G");
out.insert(b'T', b"T");
out.insert(b'U', b"T");
out.insert(b'R', b"AG");
out.insert(b'Y', b"CT");
out.insert(b'S', b"GC");
out.insert(b'W', b"AT");
out.insert(b'K', b"GT");
out.insert(b'M', b"AC");
out.insert(b'B', b"CGT");
out.insert(b'D', b"AGT");
out.insert(b'H', b"ACT");
out.insert(b'V', b"ACG");
out.insert(b'N', b"ACGT");
out.insert(b'a', b"A");
out.insert(b'c', b"C");
out.insert(b'g', b"G");
out.insert(b't', b"T");
out.insert(b'u', b"T");
out.insert(b'r', b"AG");
out.insert(b'y', b"CT");
out.insert(b's', b"GC");
out.insert(b'w', b"AT");
out.insert(b'k', b"GT");
out.insert(b'm', b"AC");
out.insert(b'b', b"CGT");
out.insert(b'd', b"AGT");
out.insert(b'h', b"ACT");
out.insert(b'v', b"ACG");
out.insert(b'n', b"ACGT");
out
}
#[test]
fn disambiguate() {
for (residue, possibilities) in ambig_residues() {
if possibilities.contains(&b'A') {
assert!(DnaDisambiguation::maybe_a(residue));
assert!(DnaDisambiguation::maybe_ac(residue));
assert!(DnaDisambiguation::maybe_ag(residue));
assert!(DnaDisambiguation::maybe_at(residue));
assert!(DnaDisambiguation::maybe_acg(residue));
assert!(DnaDisambiguation::maybe_act(residue));
assert!(DnaDisambiguation::maybe_agt(residue));
assert!(DnaDisambiguation::maybe_acgt(residue));
} else {
assert!(!DnaDisambiguation::maybe_a(residue));
}
if possibilities.contains(&b'C') {
assert!(DnaDisambiguation::maybe_c(residue));
assert!(DnaDisambiguation::maybe_ac(residue));
assert!(DnaDisambiguation::maybe_cg(residue));
assert!(DnaDisambiguation::maybe_ct(residue));
assert!(DnaDisambiguation::maybe_acg(residue));
assert!(DnaDisambiguation::maybe_act(residue));
assert!(DnaDisambiguation::maybe_cgt(residue));
assert!(DnaDisambiguation::maybe_acgt(residue));
} else {
assert!(!DnaDisambiguation::maybe_c(residue));
}
if possibilities.contains(&b'G') {
assert!(DnaDisambiguation::maybe_g(residue));
assert!(DnaDisambiguation::maybe_ag(residue));
assert!(DnaDisambiguation::maybe_cg(residue));
assert!(DnaDisambiguation::maybe_gt(residue));
assert!(DnaDisambiguation::maybe_acg(residue));
assert!(DnaDisambiguation::maybe_agt(residue));
assert!(DnaDisambiguation::maybe_cgt(residue));
assert!(DnaDisambiguation::maybe_acgt(residue));
} else {
assert!(!DnaDisambiguation::maybe_g(residue));
}
if possibilities.contains(&b'T') {
assert!(DnaDisambiguation::maybe_t(residue));
assert!(DnaDisambiguation::maybe_at(residue));
assert!(DnaDisambiguation::maybe_ct(residue));
assert!(DnaDisambiguation::maybe_gt(residue));
assert!(DnaDisambiguation::maybe_act(residue));
assert!(DnaDisambiguation::maybe_agt(residue));
assert!(DnaDisambiguation::maybe_cgt(residue));
assert!(DnaDisambiguation::maybe_acgt(residue));
} else {
assert!(!DnaDisambiguation::maybe_t(residue));
}
}
}
#[test]
fn maybe_stop_codon() {
let ambig_residues = ambig_residues();
let residues_t = ambig_residues
.iter()
.filter_map(|(residue, possibilities)| possibilities.contains(&b'T').then_some(*residue))
.collect::<Vec<_>>();
let residues_a = ambig_residues
.iter()
.filter_map(|(residue, possibilities)| possibilities.contains(&b'A').then_some(*residue))
.collect::<Vec<_>>();
let residues_g = ambig_residues
.iter()
.filter_map(|(residue, possibilities)| possibilities.contains(&b'G').then_some(*residue))
.collect::<Vec<_>>();
for residue1 in &residues_t {
for residue2 in &residues_a {
for residue3 in &residues_a {
let stop_codon = [*residue1, *residue2, *residue3];
assert!(stop_codon.maybe_std_stop_codon());
}
}
}
for residue1 in &residues_t {
for residue2 in &residues_a {
for residue3 in &residues_g {
let stop_codon = [*residue1, *residue2, *residue3];
assert!(stop_codon.maybe_std_stop_codon());
}
}
}
for residue1 in &residues_t {
for residue2 in &residues_g {
for residue3 in &residues_a {
let stop_codon = [*residue1, *residue2, *residue3];
assert!(stop_codon.maybe_std_stop_codon());
}
}
}
for residue1 in &residues_t {
for residue2 in &residues_g {
if DnaDisambiguation::maybe_a(*residue2) {
continue;
}
for residue3 in &residues_g {
if DnaDisambiguation::maybe_a(*residue3) {
continue;
}
let stop_codon = [*residue1, *residue2, *residue3];
assert!(!stop_codon.maybe_std_stop_codon());
}
}
}
}
#[test]
#[allow(clippy::reversed_empty_ranges)]
#[should_panic(expected = "Attempted to map to a range of a different length!")]
fn test_singleton_with_empty() {
use crate::data::mappings::ByteMap;
let map = ByteMap::identity().map_range(5..=5, 9..=8);
assert_eq!(map[5], 5);
}