1use crate::read_filter::ReadFilter;
42use rust_htslib::bam::{pileup::Alignment, record::Record};
43use strum::EnumString;
44
45use std::cmp::Ordering;
46
47#[derive(Copy, Clone, Debug)]
49pub enum Base {
50 A,
52 C,
54 T,
56 G,
58 N,
60 R,
62 Y,
64 S,
66 W,
68 K,
70 M,
72 B,
74 D,
76 H,
78 V,
80 }
82
83impl Base {
84 pub(crate) fn either_or<const DEFAULT_TO_N: bool>(a: Self, b: Self) -> Self {
86 match (a, b) {
87 (Self::A, Self::A) => Self::A,
88 (Self::C, Self::C) => Self::C,
89 (Self::G, Self::G) => Self::G,
90 (Self::T, Self::T) => Self::T,
91 (Self::A, Self::G) | (Self::G, Self::A) if !DEFAULT_TO_N => Self::R,
92 (Self::C, Self::T) | (Self::T, Self::C) if !DEFAULT_TO_N => Self::Y,
93 (Self::G, Self::C) | (Self::C, Self::G) if !DEFAULT_TO_N => Self::S,
94 (Self::A, Self::T) | (Self::T, Self::A) if !DEFAULT_TO_N => Self::W,
95 (Self::G, Self::T) | (Self::T, Self::G) if !DEFAULT_TO_N => Self::K,
96 (Self::A, Self::C) | (Self::C, Self::A) if !DEFAULT_TO_N => Self::M,
97 (_, _) => Self::N,
98 }
99 }
100}
101
102impl From<char> for Base {
103 #[inline]
107 fn from(value: char) -> Self {
108 match value.to_ascii_uppercase() {
109 'A' => Self::A,
110 'C' => Self::C,
111 'T' | 'U' => Self::T,
112 'G' => Self::G,
113 _ => Self::N,
114 }
115 }
116}
117
118#[derive(Debug, Copy, Clone)]
124pub struct MateResolution {
125 pub(crate) ordering: Ordering,
127 pub(crate) recommended_base: Option<Base>,
129}
130
131impl MateResolution {
132 pub(crate) fn new(ordering: Ordering, recommended_base: Option<Base>) -> Self {
133 Self {
134 ordering,
135 recommended_base,
136 }
137 }
138}
139
140#[derive(Debug, Copy, Clone, EnumString)]
148#[strum(ascii_case_insensitive)]
149pub enum MateResolutionStrategy {
150 BaseQualMapQualFirstInPair,
157
158 BaseQualMapQualIUPAC,
165
166 BaseQualMapQualN,
173
174 MapQualBaseQualFirstInPair,
181
182 MapQualBaseQualIUPAC,
189
190 MapQualBaseQualN,
197
198 IUPAC,
204
205 N,
211
212 Original,
219}
220
221impl MateResolutionStrategy {
222 pub(crate) fn cmp<F: ReadFilter>(
223 &self,
224 a: &(Alignment<'_>, Record),
225 b: &(Alignment<'_>, Record),
226 read_filter: &F,
227 ) -> MateResolution {
228 let a_pass = read_filter.filter_read(&a.1, Some(&a.0));
230 let b_pass = read_filter.filter_read(&b.1, Some(&b.0));
231 if a_pass && !b_pass {
232 return MateResolution::new(Ordering::Greater, None);
233 } else if b_pass && !a_pass {
234 return MateResolution::new(Ordering::Less, None);
235 } else if !a_pass && !b_pass {
236 return MateResolution::new(Ordering::Greater, None);
237 }
238
239 match self {
240 MateResolutionStrategy::BaseQualMapQualFirstInPair => {
241 Self::base_qual_map_qual_first_in_pair(a, b)
242 }
243 MateResolutionStrategy::BaseQualMapQualIUPAC => Self::base_qual_map_qual_iupac(a, b),
244 MateResolutionStrategy::BaseQualMapQualN => Self::base_qual_map_qual_n(a, b),
245 MateResolutionStrategy::MapQualBaseQualFirstInPair => {
246 Self::map_qual_base_qual_first_in_pair(a, b)
247 }
248 MateResolutionStrategy::MapQualBaseQualIUPAC => Self::map_qual_base_qual_iupac(a, b),
249 MateResolutionStrategy::MapQualBaseQualN => Self::map_qual_base_qual_n(a, b),
250 MateResolutionStrategy::IUPAC => Self::resolve_base::<false>(a, b),
251 MateResolutionStrategy::N => Self::resolve_base::<true>(a, b),
252 MateResolutionStrategy::Original => Self::original(a, b),
253 }
254 }
255
256 pub(crate) fn resolve_base<const DEFAULT_TO_N: bool>(
257 a: &(Alignment<'_>, Record),
258 b: &(Alignment<'_>, Record),
259 ) -> MateResolution {
260 let a_is_not_base = a.0.qpos().is_none();
262 let b_is_not_base = b.0.qpos().is_none();
263 if a_is_not_base || b_is_not_base {
264 return Self::original(a, b);
265 }
266
267 let a_base = Base::from(a.1.seq()[a.0.qpos().unwrap()] as char);
268 let b_base = Base::from(b.1.seq()[b.0.qpos().unwrap()] as char);
269 MateResolution::new(
270 Ordering::Greater,
271 Some(Base::either_or::<DEFAULT_TO_N>(a_base, b_base)),
272 )
273 }
274
275 pub(crate) fn base_qual_map_qual_n(
276 a: &(Alignment<'_>, Record),
277 b: &(Alignment<'_>, Record),
278 ) -> MateResolution {
279 let a_is_not_base = a.0.qpos().is_none();
281 let b_is_not_base = b.0.qpos().is_none();
282 if a_is_not_base || b_is_not_base {
283 return Self::original(a, b);
284 }
285
286 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
288 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
289
290 match a_qual.cmp(&b_qual) {
291 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
292 Ordering::Less => MateResolution::new(Ordering::Less, None),
293 Ordering::Equal => match a.1.mapq().cmp(&b.1.mapq()) {
294 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
295 Ordering::Less => MateResolution::new(Ordering::Less, None),
296 Ordering::Equal => {
297 let a_base = Base::from(a.1.seq()[a.0.qpos().unwrap()] as char);
298 let b_base = Base::from(b.1.seq()[b.0.qpos().unwrap()] as char);
299 let base = Base::either_or::<true>(a_base, b_base);
300 MateResolution::new(Ordering::Greater, Some(base)) }
302 },
303 }
304 }
305
306 pub(crate) fn base_qual_map_qual_iupac(
307 a: &(Alignment<'_>, Record),
308 b: &(Alignment<'_>, Record),
309 ) -> MateResolution {
310 let a_is_not_base = a.0.qpos().is_none();
312 let b_is_not_base = b.0.qpos().is_none();
313 if a_is_not_base || b_is_not_base {
314 return Self::original(a, b);
315 }
316
317 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
319 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
320
321 match a_qual.cmp(&b_qual) {
322 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
323 Ordering::Less => MateResolution::new(Ordering::Less, None),
324 Ordering::Equal => match a.1.mapq().cmp(&b.1.mapq()) {
325 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
326 Ordering::Less => MateResolution::new(Ordering::Less, None),
327 Ordering::Equal => {
328 let a_base = Base::from(a.1.seq()[a.0.qpos().unwrap()] as char);
329 let b_base = Base::from(b.1.seq()[b.0.qpos().unwrap()] as char);
330 MateResolution::new(
331 Ordering::Greater,
332 Some(Base::either_or::<false>(a_base, b_base)),
333 )
334 }
335 },
336 }
337 }
338
339 pub(crate) fn base_qual_map_qual_first_in_pair(
340 a: &(Alignment<'_>, Record),
341 b: &(Alignment<'_>, Record),
342 ) -> MateResolution {
343 let a_is_not_base = a.0.qpos().is_none();
345 let b_is_not_base = b.0.qpos().is_none();
346 if a_is_not_base || b_is_not_base {
347 return Self::original(a, b);
348 }
349
350 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
352 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
353
354 match a_qual.cmp(&b_qual) {
355 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
356 Ordering::Less => MateResolution::new(Ordering::Less, None),
357 Ordering::Equal => Self::original(a, b),
358 }
359 }
360
361 pub(crate) fn map_qual_base_qual_n(
362 a: &(Alignment<'_>, Record),
363 b: &(Alignment<'_>, Record),
364 ) -> MateResolution {
365 let a_is_not_base = a.0.qpos().is_none();
367 let b_is_not_base = b.0.qpos().is_none();
368 if a_is_not_base || b_is_not_base {
369 return Self::original(a, b);
370 }
371
372 match a.1.mapq().cmp(&b.1.mapq()) {
373 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
374 Ordering::Less => MateResolution::new(Ordering::Less, None),
375 Ordering::Equal => {
376 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
377 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
378
379 match a_qual.cmp(&b_qual) {
380 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
381 Ordering::Less => MateResolution::new(Ordering::Less, None),
382 Ordering::Equal => {
383 let a_base = Base::from(a.1.seq()[a.0.qpos().unwrap()] as char);
384 let b_base = Base::from(b.1.seq()[b.0.qpos().unwrap()] as char);
385 let base = Base::either_or::<true>(a_base, b_base);
386 MateResolution::new(Ordering::Greater, Some(base)) }
388 }
389 }
390 }
391 }
392
393 pub(crate) fn map_qual_base_qual_iupac(
394 a: &(Alignment<'_>, Record),
395 b: &(Alignment<'_>, Record),
396 ) -> MateResolution {
397 let a_is_not_base = a.0.qpos().is_none();
399 let b_is_not_base = b.0.qpos().is_none();
400 if a_is_not_base || b_is_not_base {
401 return Self::original(a, b);
402 }
403
404 match a.1.mapq().cmp(&b.1.mapq()) {
405 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
406 Ordering::Less => MateResolution::new(Ordering::Less, None),
407 Ordering::Equal => {
408 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
409 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
410
411 match a_qual.cmp(&b_qual) {
412 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
413 Ordering::Less => MateResolution::new(Ordering::Less, None),
414 Ordering::Equal => {
415 let a_base = Base::from(a.1.seq()[a.0.qpos().unwrap()] as char);
416 let b_base = Base::from(b.1.seq()[b.0.qpos().unwrap()] as char);
417 MateResolution::new(
418 Ordering::Greater,
419 Some(Base::either_or::<false>(a_base, b_base)),
420 )
421 }
422 }
423 }
424 }
425 }
426
427 pub(crate) fn map_qual_base_qual_first_in_pair(
428 a: &(Alignment<'_>, Record),
429 b: &(Alignment<'_>, Record),
430 ) -> MateResolution {
431 let a_is_not_base = a.0.qpos().is_none();
433 let b_is_not_base = b.0.qpos().is_none();
434 if a_is_not_base || b_is_not_base {
435 return Self::original(a, b);
436 }
437
438 match a.1.mapq().cmp(&b.1.mapq()) {
439 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
440 Ordering::Less => MateResolution::new(Ordering::Less, None),
441 Ordering::Equal => {
442 let a_qual = a.1.qual()[a.0.qpos().unwrap()];
443 let b_qual = b.1.qual()[b.0.qpos().unwrap()];
444
445 match a_qual.cmp(&b_qual) {
446 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
447 Ordering::Less => MateResolution::new(Ordering::Less, None),
448 Ordering::Equal => {
449 if a.1.flags() & 64 != 0 {
450 MateResolution::new(Ordering::Greater, None)
451 } else if b.1.flags() & 64 != 0 {
452 MateResolution::new(Ordering::Less, None)
453 } else {
454 MateResolution::new(Ordering::Greater, None)
456 }
457 }
458 }
459 }
460 }
461 }
462
463 pub(crate) fn original(
465 a: &(Alignment<'_>, Record),
466 b: &(Alignment<'_>, Record),
467 ) -> MateResolution {
468 match a.1.mapq().cmp(&b.1.mapq()) {
469 Ordering::Greater => MateResolution::new(Ordering::Greater, None),
470 Ordering::Less => MateResolution::new(Ordering::Less, None),
471 Ordering::Equal => {
472 if a.1.flags() & 64 != 0 {
474 MateResolution::new(Ordering::Greater, None)
475 } else if b.1.flags() & 64 != 0 {
476 MateResolution::new(Ordering::Less, None)
477 } else {
478 MateResolution::new(Ordering::Greater, None)
480 }
481 }
482 }
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use rust_htslib::bam::{self, record::Record};
490
491 #[test]
496 fn test_base_either_or_identical() {
497 assert!(matches!(
498 Base::either_or::<false>(Base::A, Base::A),
499 Base::A
500 ));
501 assert!(matches!(
502 Base::either_or::<false>(Base::C, Base::C),
503 Base::C
504 ));
505 assert!(matches!(
506 Base::either_or::<false>(Base::G, Base::G),
507 Base::G
508 ));
509 assert!(matches!(
510 Base::either_or::<false>(Base::T, Base::T),
511 Base::T
512 ));
513 }
514
515 #[test]
516 fn test_base_either_or_iupac() {
517 assert!(matches!(
519 Base::either_or::<false>(Base::A, Base::G),
520 Base::R
521 ));
522 assert!(matches!(
523 Base::either_or::<false>(Base::G, Base::A),
524 Base::R
525 ));
526
527 assert!(matches!(
528 Base::either_or::<false>(Base::C, Base::T),
529 Base::Y
530 ));
531 assert!(matches!(
532 Base::either_or::<false>(Base::T, Base::C),
533 Base::Y
534 ));
535
536 assert!(matches!(
537 Base::either_or::<false>(Base::G, Base::C),
538 Base::S
539 ));
540 assert!(matches!(
541 Base::either_or::<false>(Base::C, Base::G),
542 Base::S
543 ));
544
545 assert!(matches!(
546 Base::either_or::<false>(Base::A, Base::T),
547 Base::W
548 ));
549 assert!(matches!(
550 Base::either_or::<false>(Base::T, Base::A),
551 Base::W
552 ));
553
554 assert!(matches!(
555 Base::either_or::<false>(Base::G, Base::T),
556 Base::K
557 ));
558 assert!(matches!(
559 Base::either_or::<false>(Base::T, Base::G),
560 Base::K
561 ));
562
563 assert!(matches!(
564 Base::either_or::<false>(Base::A, Base::C),
565 Base::M
566 ));
567 assert!(matches!(
568 Base::either_or::<false>(Base::C, Base::A),
569 Base::M
570 ));
571 }
572
573 #[test]
574 fn test_base_either_or_default_to_n() {
575 assert!(matches!(Base::either_or::<true>(Base::A, Base::G), Base::N));
577 assert!(matches!(Base::either_or::<true>(Base::C, Base::T), Base::N));
578 assert!(matches!(Base::either_or::<true>(Base::G, Base::C), Base::N));
579
580 assert!(matches!(Base::either_or::<true>(Base::A, Base::A), Base::A));
582 assert!(matches!(Base::either_or::<true>(Base::C, Base::C), Base::C));
583 }
584
585 #[test]
586 fn test_base_from_char() {
587 assert!(matches!(Base::from('A'), Base::A));
589 assert!(matches!(Base::from('C'), Base::C));
590 assert!(matches!(Base::from('T'), Base::T));
591 assert!(matches!(Base::from('G'), Base::G));
592
593 assert!(matches!(Base::from('a'), Base::A));
595 assert!(matches!(Base::from('c'), Base::C));
596 assert!(matches!(Base::from('t'), Base::T));
597 assert!(matches!(Base::from('g'), Base::G));
598
599 assert!(matches!(Base::from('U'), Base::T));
601 assert!(matches!(Base::from('u'), Base::T));
602
603 assert!(matches!(Base::from('X'), Base::N));
605 assert!(matches!(Base::from('?'), Base::N));
606 assert!(matches!(Base::from('1'), Base::N));
607 }
608
609 #[test]
614 fn test_mate_resolution_construction() {
615 let res = MateResolution::new(Ordering::Greater, Some(Base::N));
616 assert_eq!(res.ordering, Ordering::Greater);
617 assert!(matches!(res.recommended_base, Some(Base::N)));
618 }
619
620 #[allow(clippy::too_many_arguments)]
622 fn test_strategy_with_bam(
623 strategy: MateResolutionStrategy,
624 read1_seq: &[u8],
625 read1_qual: &[u8],
626 read1_mapq: u8,
627 read1_flags: u16,
628 read2_seq: &[u8],
629 read2_qual: &[u8],
630 read2_mapq: u8,
631 read2_flags: u16,
632 ) -> MateResolution {
633 use rust_htslib::bam::{HeaderView, IndexedReader, Read, Writer, index};
634 use tempfile::tempdir;
635
636 let tempdir = tempdir().unwrap();
637 let bam_path = tempdir.path().join("test.bam");
638
639 let mut header = bam::header::Header::new();
641 let mut chr1 = bam::header::HeaderRecord::new(b"SQ");
642 chr1.push_tag(b"SN", &"chr1".to_owned());
643 chr1.push_tag(b"LN", &"100".to_owned());
644 header.push_record(&chr1);
645 let view = HeaderView::from_header(&header);
646
647 let records = vec![
652 Record::from_sam(
653 &view,
654 format!(
655 "TESTPAIR\t{}\tchr1\t11\t{}\t10M\tchr1\t16\t30\t{}\t{}",
656 read1_flags,
657 read1_mapq,
658 std::str::from_utf8(read1_seq).unwrap(),
659 std::str::from_utf8(read1_qual).unwrap()
660 )
661 .as_bytes(),
662 )
663 .unwrap(),
664 Record::from_sam(
665 &view,
666 format!(
667 "TESTPAIR\t{}\tchr1\t16\t{}\t10M\tchr1\t11\t30\t{}\t{}",
668 read2_flags,
669 read2_mapq,
670 std::str::from_utf8(read2_seq).unwrap(),
671 std::str::from_utf8(read2_qual).unwrap()
672 )
673 .as_bytes(),
674 )
675 .unwrap(),
676 ];
677
678 let mut writer = Writer::from_path(&bam_path, &header, bam::Format::Bam).unwrap();
680 for record in &records {
681 writer.write(record).unwrap();
682 }
683 drop(writer);
684
685 index::build(&bam_path, None, index::Type::Bai, 1).unwrap();
687
688 let mut reader = IndexedReader::from_path(&bam_path).unwrap();
690 reader.fetch(("chr1", 15, 20)).unwrap(); let pileup_iter = reader.pileup();
692
693 let read_filter = crate::read_filter::DefaultReadFilter::new(0, 0, 0);
694
695 for pileup_result in pileup_iter {
696 let pileup = pileup_result.unwrap();
697 if pileup.pos() >= 15 && pileup.pos() < 20 {
698 let alns: Vec<_> = pileup
700 .alignments()
701 .map(|aln| {
702 let rec = aln.record();
703 (aln, rec)
704 })
705 .collect();
706
707 if alns.len() == 2 {
708 return strategy.cmp(&alns[0], &alns[1], &read_filter);
709 }
710 }
711 }
712
713 panic!("Failed to find overlapping reads at test position");
714 }
715
716 #[test]
717 fn test_base_qual_map_qual_first_in_pair() {
718 let result = test_strategy_with_bam(
720 MateResolutionStrategy::BaseQualMapQualFirstInPair,
721 b"AAAAAAAAAA",
722 b"##########",
723 30,
724 67, b"CCCCCCCCCC",
726 b">>>>>>>>>>",
727 30,
728 147, );
730 assert_eq!(result.ordering, Ordering::Less); assert!(result.recommended_base.is_none());
732
733 let result = test_strategy_with_bam(
735 MateResolutionStrategy::BaseQualMapQualFirstInPair,
736 b"AAAAAAAAAA",
737 b">>>>>>>>>>",
738 40,
739 67, b"CCCCCCCCCC",
741 b">>>>>>>>>>",
742 30,
743 147, );
745 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
747
748 let result = test_strategy_with_bam(
750 MateResolutionStrategy::BaseQualMapQualFirstInPair,
751 b"AAAAAAAAAA",
752 b">>>>>>>>>>",
753 30,
754 67, b"CCCCCCCCCC",
756 b">>>>>>>>>>",
757 30,
758 147, );
760 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
762 }
763
764 #[test]
765 fn test_base_qual_map_qual_iupac() {
766 let result = test_strategy_with_bam(
768 MateResolutionStrategy::BaseQualMapQualIUPAC,
769 b"AAAAAAAAAA",
770 b"##########",
771 30,
772 67, b"CCCCCCCCCC",
774 b">>>>>>>>>>",
775 30,
776 147, );
778 assert_eq!(result.ordering, Ordering::Less); assert!(result.recommended_base.is_none());
780
781 let result = test_strategy_with_bam(
783 MateResolutionStrategy::BaseQualMapQualIUPAC,
784 b"AAAAAAAAAA",
785 b">>>>>>>>>>",
786 30,
787 67, b"GGGGGGGGGG",
789 b">>>>>>>>>>",
790 30,
791 147, );
793 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::R))); }
796
797 #[test]
798 fn test_base_qual_map_qual_n() {
799 let result = test_strategy_with_bam(
801 MateResolutionStrategy::BaseQualMapQualN,
802 b"AAAAAAAAAA",
803 b"##########",
804 30,
805 67, b"CCCCCCCCCC",
807 b">>>>>>>>>>",
808 30,
809 147, );
811 assert_eq!(result.ordering, Ordering::Less); assert!(result.recommended_base.is_none());
813
814 let result = test_strategy_with_bam(
816 MateResolutionStrategy::BaseQualMapQualN,
817 b"AAAAAAAAAA",
818 b">>>>>>>>>>",
819 30,
820 67, b"CCCCCCCCCC",
822 b">>>>>>>>>>",
823 30,
824 147, );
826 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::N))); }
829
830 #[test]
831 fn test_map_qual_base_qual_first_in_pair() {
832 let result = test_strategy_with_bam(
834 MateResolutionStrategy::MapQualBaseQualFirstInPair,
835 b"AAAAAAAAAA",
836 b">>>>>>>>>>",
837 40,
838 67, b"CCCCCCCCCC",
840 b">>>>>>>>>>",
841 30,
842 147, );
844 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
846
847 let result = test_strategy_with_bam(
849 MateResolutionStrategy::MapQualBaseQualFirstInPair,
850 b"AAAAAAAAAA",
851 b"##########",
852 30,
853 67, b"CCCCCCCCCC",
855 b">>>>>>>>>>",
856 30,
857 147, );
859 assert_eq!(result.ordering, Ordering::Less); assert!(result.recommended_base.is_none());
861
862 let result = test_strategy_with_bam(
864 MateResolutionStrategy::MapQualBaseQualFirstInPair,
865 b"AAAAAAAAAA",
866 b">>>>>>>>>>",
867 30,
868 67, b"CCCCCCCCCC",
870 b">>>>>>>>>>",
871 30,
872 147, );
874 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
876 }
877
878 #[test]
879 fn test_map_qual_base_qual_iupac() {
880 let result = test_strategy_with_bam(
882 MateResolutionStrategy::MapQualBaseQualIUPAC,
883 b"AAAAAAAAAA",
884 b">>>>>>>>>>",
885 40,
886 67, b"CCCCCCCCCC",
888 b">>>>>>>>>>",
889 30,
890 147, );
892 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
894
895 let result = test_strategy_with_bam(
897 MateResolutionStrategy::MapQualBaseQualIUPAC,
898 b"AAAAAAAAAA",
899 b">>>>>>>>>>",
900 30,
901 67, b"GGGGGGGGGG",
903 b">>>>>>>>>>",
904 30,
905 147, );
907 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::R))); }
910
911 #[test]
912 fn test_map_qual_base_qual_n() {
913 let result = test_strategy_with_bam(
915 MateResolutionStrategy::MapQualBaseQualN,
916 b"AAAAAAAAAA",
917 b">>>>>>>>>>",
918 40,
919 67, b"CCCCCCCCCC",
921 b">>>>>>>>>>",
922 30,
923 147, );
925 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
927
928 let result = test_strategy_with_bam(
930 MateResolutionStrategy::MapQualBaseQualN,
931 b"AAAAAAAAAA",
932 b">>>>>>>>>>",
933 30,
934 67, b"CCCCCCCCCC",
936 b">>>>>>>>>>",
937 30,
938 147, );
940 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::N))); }
943
944 #[test]
945 fn test_iupac_strategy() {
946 let result = test_strategy_with_bam(
948 MateResolutionStrategy::IUPAC,
949 b"AAAAAAAAAA",
950 b">>>>>>>>>>",
951 30,
952 67, b"GGGGGGGGGG",
954 b">>>>>>>>>>",
955 40,
956 147, );
958 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::R))); let result = test_strategy_with_bam(
963 MateResolutionStrategy::IUPAC,
964 b"AAAAAAAAAA",
965 b">>>>>>>>>>",
966 30,
967 67, b"AAAAAAAAAA",
969 b">>>>>>>>>>",
970 40,
971 147, );
973 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::A))); }
976
977 #[test]
978 fn test_n_strategy() {
979 let result = test_strategy_with_bam(
981 MateResolutionStrategy::N,
982 b"AAAAAAAAAA",
983 b">>>>>>>>>>",
984 30,
985 67, b"CCCCCCCCCC",
987 b">>>>>>>>>>",
988 40,
989 147, );
991 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::N))); let result = test_strategy_with_bam(
996 MateResolutionStrategy::N,
997 b"AAAAAAAAAA",
998 b">>>>>>>>>>",
999 30,
1000 67, b"AAAAAAAAAA",
1002 b">>>>>>>>>>",
1003 40,
1004 147, );
1006 assert_eq!(result.ordering, Ordering::Greater); assert!(matches!(result.recommended_base, Some(Base::A))); }
1009
1010 #[test]
1011 fn test_original_strategy() {
1012 let result = test_strategy_with_bam(
1014 MateResolutionStrategy::Original,
1015 b"AAAAAAAAAA",
1016 b">>>>>>>>>>",
1017 40,
1018 67, b"CCCCCCCCCC",
1020 b">>>>>>>>>>",
1021 30,
1022 147, );
1024 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
1026
1027 let result = test_strategy_with_bam(
1029 MateResolutionStrategy::Original,
1030 b"AAAAAAAAAA",
1031 b">>>>>>>>>>",
1032 30,
1033 67, b"CCCCCCCCCC",
1035 b">>>>>>>>>>",
1036 30,
1037 147, );
1039 assert_eq!(result.ordering, Ordering::Greater); assert!(result.recommended_base.is_none());
1041
1042 let result = test_strategy_with_bam(
1044 MateResolutionStrategy::Original,
1045 b"AAAAAAAAAA",
1046 b">>>>>>>>>>",
1047 30,
1048 147, b"CCCCCCCCCC",
1050 b">>>>>>>>>>",
1051 30,
1052 67, );
1054 assert_eq!(result.ordering, Ordering::Less); assert!(result.recommended_base.is_none());
1056 }
1057}