Skip to content

Commit fae5021

Browse files
committed
Populate condition-coverage field in cobertura xml reports
Some parsers require the presence of the `condition-coverage` field on the `line` elements in the report. This change adds and populates this field based on the available `Conditions` data. See: https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-03.dtd Implements #1029
1 parent 5175fd1 commit fae5021

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/cobertura.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@ fn write_lines(writer: &mut Writer<Cursor<Vec<u8>>>, lines: &[Line]) {
530530
l.push_attribute(("number", number.to_string().as_ref()));
531531
l.push_attribute(("hits", hits.to_string().as_ref()));
532532
l.push_attribute(("branch", "true"));
533+
l.push_attribute((
534+
"condition-coverage",
535+
format_condition_coverage(conditions).as_ref(),
536+
));
537+
533538
writer.write_event(Event::Start(l)).unwrap();
534539

535540
let conditions_tag = "conditions";
@@ -562,6 +567,33 @@ fn write_lines(writer: &mut Writer<Cursor<Vec<u8>>>, lines: &[Line]) {
562567
.unwrap();
563568
}
564569

570+
fn format_condition_coverage(conditions: &[Condition]) -> String {
571+
let conditions_hit: f64 = conditions.iter().map(|c| c.coverage).sum();
572+
let num_conditions = conditions.len();
573+
if num_conditions > 0 {
574+
format!(
575+
"{:.0}% ({:.0}/{})",
576+
100.0 * conditions_hit / num_conditions as f64,
577+
conditions_hit,
578+
num_conditions
579+
)
580+
} else {
581+
// It's unclear what this should be, so we set it to 100% to avoid potentially affecting results
582+
use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
583+
584+
static HAVE_PRINTED_WARNING: AtomicBool = AtomicBool::new(false);
585+
// Print a warning about symbolic links, but only once per grcov run.
586+
if HAVE_PRINTED_WARNING
587+
.compare_exchange(false, true, SeqCst, SeqCst)
588+
.is_ok()
589+
{
590+
eprintln!("Encountered a branch with zero conditions, returning 100% condition coverage as a precausion.");
591+
}
592+
593+
"100% (0/0)".to_owned()
594+
}
595+
}
596+
565597
#[cfg(test)]
566598
mod tests {
567599
use super::*;
@@ -860,4 +892,26 @@ mod tests {
860892
assert!(results.contains(r#"<source>src</source>"#));
861893
assert!(results.contains(r#"package name="main.rs""#));
862894
}
895+
896+
#[test]
897+
fn test_condition_coverage() {
898+
const HIT: Condition = Condition {
899+
coverage: 1.0,
900+
number: 0,
901+
cond_type: ConditionType::Jump,
902+
};
903+
const MISS: Condition = Condition {
904+
coverage: 0.0,
905+
number: 0,
906+
cond_type: ConditionType::Jump,
907+
};
908+
909+
assert_eq!("100% (1/1)", format_condition_coverage(&[HIT]));
910+
assert_eq!("0% (0/1)", format_condition_coverage(&[MISS]));
911+
assert_eq!("50% (1/2)", format_condition_coverage(&[HIT, MISS]));
912+
assert_eq!("33% (1/3)", format_condition_coverage(&[HIT, MISS, MISS]));
913+
assert_eq!("67% (2/3)", format_condition_coverage(&[HIT, HIT, MISS]));
914+
915+
assert_eq!("100% (0/0)", format_condition_coverage(&[]));
916+
}
863917
}

0 commit comments

Comments
 (0)