diff --git a/src/fastp.rs b/src/fastp.rs index d3dbcce..c4f8072 100644 --- a/src/fastp.rs +++ b/src/fastp.rs @@ -178,17 +178,29 @@ fn merge_adapter_counts(dicts: &[&Map]) -> Result Result { const FIELDS: &[&str] = &[ "passed_filter_reads", "low_quality_reads", "too_many_N_reads", + "adapter_dimer_reads", "too_short_reads", "too_long_reads", ]; + let has_dimer = results + .iter() + .any(|r| r.get("adapter_dimer_reads").is_some()); + let mut merged = Map::new(); for field in FIELDS { + if *field == "adapter_dimer_reads" && !has_dimer { + continue; + } let mut sum = 0_i64; for (i, result) in results.iter().enumerate() { sum += required_i64(result, field).with_context(|| format!("filtering_result[{i}]"))?; diff --git a/tests/fastp_test.rs b/tests/fastp_test.rs index 045b67f..41e9e54 100644 --- a/tests/fastp_test.rs +++ b/tests/fastp_test.rs @@ -191,8 +191,48 @@ fn test_merge_two_fixture_files_filtering_result() { assert_eq!(fr["passed_filter_reads"].as_i64(), Some(2850)); assert_eq!(fr["low_quality_reads"].as_i64(), Some(90)); assert_eq!(fr["too_many_N_reads"].as_i64(), Some(30)); + assert_eq!(fr["adapter_dimer_reads"].as_i64(), Some(408)); assert_eq!(fr["too_short_reads"].as_i64(), Some(30)); assert_eq!(fr["too_long_reads"].as_i64(), Some(0)); + + // adapter_dimer_reads must keep fastp's field order: between too_many_N_reads + // and too_short_reads. + let keys: Vec<&str> = fr.as_object().unwrap().keys().map(String::as_str).collect(); + assert_eq!( + keys, + [ + "passed_filter_reads", + "low_quality_reads", + "too_many_N_reads", + "adapter_dimer_reads", + "too_short_reads", + "too_long_reads", + ] + ); +} + +#[test] +fn test_merge_filtering_result_omits_adapter_dimer_when_absent() { + // Older fastp versions predate adapter_dimer_reads; merging must not invent it. + let chunk = json!({ + "summary": { + "before_filtering": {"total_reads": 10, "total_bases": 100, "q20_bases": 90, "q30_bases": 80}, + "after_filtering": {"total_reads": 10, "total_bases": 100, "q20_bases": 90, "q30_bases": 80} + }, + "filtering_result": { + "passed_filter_reads": 10, + "low_quality_reads": 0, + "too_many_N_reads": 0, + "too_short_reads": 0, + "too_long_reads": 0 + }, + "duplication": {"rate": 0.0}, + "adapter_cutting": {"adapter_trimmed_reads": 0, "adapter_trimmed_bases": 0} + }); + let merged = merge_jsons(&[chunk.clone(), chunk]).expect("merge should succeed"); + let fr = &merged["filtering_result"]; + assert!(fr.get("adapter_dimer_reads").is_none()); + assert_eq!(fr["passed_filter_reads"].as_i64(), Some(20)); } #[test] diff --git a/tests/fixtures/fastp_chunk1.json b/tests/fixtures/fastp_chunk1.json index af3b700..5872eb8 100644 --- a/tests/fixtures/fastp_chunk1.json +++ b/tests/fixtures/fastp_chunk1.json @@ -29,6 +29,7 @@ "passed_filter_reads": 950, "low_quality_reads": 30, "too_many_N_reads": 10, + "adapter_dimer_reads": 203, "too_short_reads": 10, "too_long_reads": 0 }, diff --git a/tests/fixtures/fastp_chunk2.json b/tests/fixtures/fastp_chunk2.json index 281a13b..5640e74 100644 --- a/tests/fixtures/fastp_chunk2.json +++ b/tests/fixtures/fastp_chunk2.json @@ -29,6 +29,7 @@ "passed_filter_reads": 1900, "low_quality_reads": 60, "too_many_N_reads": 20, + "adapter_dimer_reads": 205, "too_short_reads": 20, "too_long_reads": 0 },