Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum ItemFormat {
Profraw,
Profdata,
Info,
JacocoXml,
Xml,
}

#[derive(Debug)]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,13 @@ pub fn consumer(
continue;
}
}
ItemFormat::Info | ItemFormat::JacocoXml => {
ItemFormat::Info | ItemFormat::Xml => {
if let ItemType::Content(content) = work_item.item {
if work_item.format == ItemFormat::Info {
try_parse!(parse_lcov(content, branch_enabled), work_item.name)
} else {
let buffer = BufReader::new(Cursor::new(content));
try_parse!(parse_jacoco_xml_report(buffer), work_item.name)
try_parse!(parse_xml_report(buffer), work_item.name)
}
} else {
error!("Invalid content type");
Expand Down
109 changes: 97 additions & 12 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,68 @@ fn get_xml_attribute<R: BufRead>(
)))
}

fn parse_jacoco_report_sourcefile<T: BufRead>(
pub fn parse_scoverage_class<T: BufRead>(
reader: &mut Reader<T>,
buf: &mut Vec<u8>,
) -> Result<CovResult, ParserError> {
let mut lines: BTreeMap<u32, u64> = BTreeMap::new();
let mut branches: BTreeMap<u32, Vec<bool>> = BTreeMap::new();

loop {
match reader.read_event_into(buf) {
Ok(Event::Start(ref event)) if event.local_name().into_inner() == b"statement" => {
let line = get_xml_attribute(reader, event, "line")?.parse::<u32>()?;
let branch = get_xml_attribute(reader, event, "branch")? == "true";
let invoked = get_xml_attribute(reader, event, "invocation-count")?.parse::<u64>()?;

lines.entry(line).and_modify(|v| *v = invoked).or_insert(invoked);
if branch {
branches.entry(line).and_modify(|v| {
v.push(invoked > 0);
}).or_insert(vec![invoked > 0]);
}
}
Ok(Event::End(ref e)) if e.local_name().into_inner() == b"class" => {
return Ok(CovResult {
lines,
branches,
functions: FxHashMap::default(),
});
}
Err(e) => return Err(ParserError::Parse(e.to_string())),
_ => {}
}
}
}

pub fn parse_scoverage_report_packages<T: BufRead>(
parser: &mut Reader<T>,
buf: &mut Vec<u8>,
) -> Result<Vec<(String, CovResult)>, ParserError> {
let mut results_map: FxHashMap<String, CovResult> = FxHashMap::default();
loop {

match parser.read_event_into(buf) {
Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"class" => {
let file = get_xml_attribute(parser, e, "filename")?.replace('.', "/").replace("/scala", ".scala");
let results = parse_scoverage_class(parser, buf)?;

results_map.entry(file.to_string()).and_modify(|v| {
v.lines.extend(results.lines.clone());
v.branches.extend(results.branches.clone());
}).or_insert(results);
}
Err(e) => return Err(ParserError::Parse(e.to_string())),
Ok(Event::End(ref e)) if e.local_name().into_inner() == b"scoverage" => {
return Ok(results_map.into_iter().collect());
}
_ => {}
}
}
}


fn parse_report_sourcefile<T: BufRead>(
parser: &mut Reader<T>,
buf: &mut Vec<u8>,
) -> Result<JacocoReport, ParserError> {
Expand Down Expand Up @@ -679,7 +740,7 @@ fn parse_jacoco_report_sourcefile<T: BufRead>(
Ok(JacocoReport { lines, branches })
}

fn parse_jacoco_report_method<T: BufRead>(
fn parse_report_method<T: BufRead>(
parser: &mut Reader<T>,
buf: &mut Vec<u8>,
start: u32,
Expand All @@ -703,7 +764,7 @@ fn parse_jacoco_report_method<T: BufRead>(
Ok(Function { start, executed })
}

fn parse_jacoco_report_class<T: BufRead>(
fn parse_report_class<T: BufRead>(
parser: &mut Reader<T>,
buf: &mut Vec<u8>,
class_name: &str,
Expand All @@ -717,7 +778,7 @@ fn parse_jacoco_report_class<T: BufRead>(
let full_name = format!("{}#{}", class_name, name);

let start_line = get_xml_attribute(parser, e, "line")?.parse::<u32>()?;
let function = parse_jacoco_report_method(parser, buf, start_line)?;
let function = parse_report_method(parser, buf, start_line)?;
functions.insert(full_name, function);
}
Ok(Event::End(ref e)) if e.local_name().into_inner() == b"class" => break,
Expand All @@ -730,7 +791,7 @@ fn parse_jacoco_report_class<T: BufRead>(
Ok(functions)
}

fn parse_jacoco_report_package<T: BufRead>(
fn parse_report_package<T: BufRead>(
parser: &mut Reader<T>,
buf: &mut Vec<u8>,
package: &str,
Expand Down Expand Up @@ -760,7 +821,7 @@ fn parse_jacoco_report_package<T: BufRead>(
.unwrap_or(format!("{}.java", top_class));

// Process all <method /> and <counter /> for this class
let functions = parse_jacoco_report_class(parser, buf, class)?;
let functions = parse_report_class(parser, buf, class)?;

match results_map.entry(file.to_string()) {
hash_map::Entry::Occupied(obj) => {
Expand All @@ -780,7 +841,7 @@ fn parse_jacoco_report_package<T: BufRead>(
let file = get_xml_attribute(parser, e, "name")?;

let JacocoReport { lines, branches } =
parse_jacoco_report_sourcefile(parser, buf)?;
parse_report_sourcefile(parser, buf)?;

match results_map.entry(file.to_string()) {
hash_map::Entry::Occupied(obj) => {
Expand Down Expand Up @@ -822,7 +883,7 @@ fn parse_jacoco_report_package<T: BufRead>(
.collect())
}

pub fn parse_jacoco_xml_report<T: Read>(
pub fn parse_xml_report<T: Read>(
xml_reader: BufReader<T>,
) -> Result<Vec<(String, CovResult)>, ParserError> {
let mut parser = Reader::from_reader(xml_reader);
Expand All @@ -835,10 +896,14 @@ pub fn parse_jacoco_xml_report<T: Read>(

loop {
match parser.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"scoverage" => {
let mut package_results = parse_scoverage_report_packages(&mut parser, &mut buf)?;
results.append(&mut package_results);
}
Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"package" => {
let package = get_xml_attribute(&parser, e, "name")?;
let mut package_results =
parse_jacoco_report_package(&mut parser, &mut buf, &package)?;
parse_report_package(&mut parser, &mut buf, &package)?;
results.append(&mut package_results);
}
Ok(Event::Eof) => break,
Expand Down Expand Up @@ -2032,7 +2097,7 @@ TN:http_3a_2f_2fweb_2dplatform_2etest_3a8000_2freferrer_2dpolicy_2fgen_2fsrcdoc_

let f = File::open("./test/jacoco/basic-report.xml").expect("Failed to open xml file");
let file = BufReader::new(&f);
let results = parse_jacoco_xml_report(file).unwrap();
let results = parse_xml_report(file).unwrap();

assert_eq!(results, expected);
}
Expand Down Expand Up @@ -2079,7 +2144,7 @@ TN:http_3a_2f_2fweb_2dplatform_2etest_3a8000_2freferrer_2dpolicy_2fgen_2fsrcdoc_

let f = File::open("./test/jacoco/inner-classes.xml").expect("Failed to open xml file");
let file = BufReader::new(&f);
let results = parse_jacoco_xml_report(file).unwrap();
let results = parse_xml_report(file).unwrap();

assert_eq!(results, expected);
}
Expand Down Expand Up @@ -2154,7 +2219,27 @@ TN:http_3a_2f_2fweb_2dplatform_2etest_3a8000_2freferrer_2dpolicy_2fgen_2fsrcdoc_
let f =
File::open("./test/jacoco/kotlin-jacoco-report.xml").expect("Failed to open xml file");
let file = BufReader::new(&f);
let results = parse_jacoco_xml_report(file).unwrap();
let results = parse_xml_report(file).unwrap();
assert_eq!(results, expected);
}

#[test]
fn parse_scoverage() {
let mut lines = BTreeMap::new();
lines.insert(5, 1);
lines.insert(6, 1);
lines.insert(8, 0);
let mut branches = BTreeMap::new();
branches.insert(6, vec![true]);
branches.insert(8, vec![false]);

let expected = vec![
(String::from("Example2.scala"), CovResult { lines, branches, functions: FxHashMap::default() })
];

let f = File::open("./test/scoverage.xml").expect("Failed to open scoverage coverage file");
let file = BufReader::new(&f);
let results = parse_xml_report(file).unwrap();
assert_eq!(results, expected);
}
}
2 changes: 1 addition & 1 deletion src/path_rewriting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ fn to_globset(dirs: &[impl AsRef<str>]) -> GlobSet {
glob_builder.build().unwrap()
}

const PARTIAL_PATH_EXTENSION: &[&str] = &["java", "kt"];
const PARTIAL_PATH_EXTENSION: &[&str] = &["java", "kt", "scala"];

pub fn rewrite_paths(
result_map: CovResultMap,
Expand Down
47 changes: 29 additions & 18 deletions src/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Archive {
}
}
"xml" => {
if Archive::check_file(file, &Archive::is_jacoco) {
if Archive::check_file(file, &Archive::is_supported_xml_format) {
let filename = clean_path(path);
self.insert_vec(filename, xmls);
}
Expand All @@ -119,11 +119,11 @@ impl Archive {
&& (&bytes[5..] == b"204" || &bytes[5..] == b"804")
}

fn is_jacoco(reader: &mut dyn Read) -> bool {
fn is_supported_xml_format(reader: &mut dyn Read) -> bool {
let mut bytes: [u8; 256] = [0; 256];
if reader.read_exact(&mut bytes).is_ok() {
return match String::from_utf8(bytes.to_vec()) {
Ok(s) => s.contains("-//JACOCO//DTD"),
Ok(s) => s.contains("-//JACOCO//DTD") || s.contains("<coverage") || s.contains("<scoverage"),
Err(_) => false,
};
}
Expand Down Expand Up @@ -574,7 +574,7 @@ pub fn producer(
);

file_content_producer(&infos.into_inner(), sender, ItemFormat::Info);
file_content_producer(&xmls.into_inner(), sender, ItemFormat::JacocoXml);
file_content_producer(&xmls.into_inner(), sender, ItemFormat::Xml);
llvm_format_producer(
tmp_dir,
&profdatas.into_inner(),
Expand Down Expand Up @@ -753,31 +753,31 @@ mod tests {
(ItemFormat::Gcno, false, "llvm/file_branch", true),
(ItemFormat::Gcno, false, "llvm/reader", true),
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/basic-jacoco.xml",
false,
),
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/inner-classes.xml",
false,
),
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/multiple-top-level-classes.xml",
false,
),
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/full-junit4-report-multiple-top-level-classes.xml",
false,
),
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/kotlin-jacoco-report.xml",
false,
Expand All @@ -789,6 +789,12 @@ mod tests {
"mozillavpn_serverconnection_1.gcno",
true,
),
(
ItemFormat::Xml,
false,
"test/scoverage.xml",
false
)
];

check_produced(tmp_path, &receiver, expected);
Expand Down Expand Up @@ -1169,12 +1175,12 @@ mod tests {

let expected = vec![
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/basic-jacoco.xml",
true,
),
(ItemFormat::JacocoXml, false, "inner-classes.xml", true),
(ItemFormat::Xml, false, "inner-classes.xml", true),
];

check_produced(tmp_path, &receiver, expected);
Expand Down Expand Up @@ -1202,12 +1208,12 @@ mod tests {

let expected = vec![
(
ItemFormat::JacocoXml,
ItemFormat::Xml,
false,
"jacoco/basic-jacoco.xml",
true,
),
(ItemFormat::JacocoXml, false, "inner-classes.xml", true),
(ItemFormat::Xml, false, "inner-classes.xml", true),
(ItemFormat::Info, false, "1494603967-2977-2_0.info", true),
(ItemFormat::Info, false, "1494603967-2977-3_0.info", true),
(ItemFormat::Info, false, "1494603967-2977-4_0.info", true),
Expand Down Expand Up @@ -1649,30 +1655,35 @@ mod tests {
fn test_jacoco_files() {
let mut file = File::open("./test/jacoco/basic-report.xml").ok();
assert!(
Archive::check_file(file.as_mut(), &Archive::is_jacoco),
Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"A Jacoco XML file expected"
);
let mut file =
File::open("./test/jacoco/full-junit4-report-multiple-top-level-classes.xml").ok();
assert!(
Archive::check_file(file.as_mut(), &Archive::is_jacoco),
Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"A Jacoco XML file expected"
);
let mut file = File::open("./test/jacoco/inner-classes.xml").ok();
assert!(
Archive::check_file(file.as_mut(), &Archive::is_jacoco),
Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"A Jacoco XML file expected"
);
let mut file = File::open("./test/jacoco/multiple-top-level-classes.xml").ok();
assert!(
Archive::check_file(file.as_mut(), &Archive::is_jacoco),
Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"A Jacoco XML file expected"
);
let mut file = File::open("./test/jacoco/not_jacoco_file.xml").ok();
assert!(
!Archive::check_file(file.as_mut(), &Archive::is_jacoco),
!Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"Not a Jacoco XML file expected"
);
let mut file = File::open("./test/scoverage.xml").ok();
assert!(
Archive::check_file(file.as_mut(), &Archive::is_supported_xml_format),
"An Scoverage XML file expected"
);
}

#[test]
Expand Down
Loading
Loading