diff --git a/src/errors/mod.rs b/src/errors/mod.rs index f00e0db1ce..9c663b91e0 100644 --- a/src/errors/mod.rs +++ b/src/errors/mod.rs @@ -1,5 +1,5 @@ -use failure::Fail; use crate::report::cobertura; +use failure::Fail; /// Error states that could be returned from tarpaulin #[derive(Fail, Debug)] pub enum RunError { diff --git a/src/lib.rs b/src/lib.rs index 90be24cc31..7a2ffa7b61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use crate::traces::*; use cargo::core::{compiler::CompileMode, Package, Shell, Workspace}; use cargo::ops; use cargo::util::{homedir, Config as CargoConfig}; -use log::{debug, info, warn, trace}; +use log::{debug, info, trace, warn}; use nix::unistd::*; use std::env; use std::ffi::CString; @@ -29,7 +29,7 @@ mod ptrace_control; pub fn run(config: &Config) -> Result<(), RunError> { let (tracemap, ret) = launch_tarpaulin(config)?; report_coverage(config, &tracemap)?; - + if ret == 0 { Ok(()) } else { @@ -128,7 +128,6 @@ pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> { } } - fn setup_environment(config: &Config) { let rustflags = "RUSTFLAGS"; let mut value = @@ -143,7 +142,6 @@ fn setup_environment(config: &Config) { env::set_var(rustflags, value); } - fn accumulate_lines( (mut acc, mut group): (Vec, Vec), next: u64, @@ -224,8 +222,7 @@ pub fn report_coverage(config: &Config, result: &TraceMap) -> Result<(), RunErro for g in &config.generate { match *g { OutputFile::Xml => { - report::cobertura::report(result, config) - .map_err(|e| RunError::XML(e))?; + report::cobertura::report(result, config).map_err(|e| RunError::XML(e))?; } OutputFile::Html => { report::html::export(result, config)?; diff --git a/src/main.rs b/src/main.rs index e22add5fbe..b70e935459 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,9 @@ use cargo_tarpaulin::run; use clap::{crate_version, App, Arg, ArgSettings, SubCommand}; use env_logger::Builder; use log::error; +use log::trace; use std::io::Write; use std::path::Path; -use log::trace; fn is_dir(d: String) -> Result<(), String> { if Path::new(&d).is_dir() { diff --git a/src/report/cobertura.rs b/src/report/cobertura.rs index 00de4d53be..5397d36620 100644 --- a/src/report/cobertura.rs +++ b/src/report/cobertura.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] /// The XML structure for a cobatura report is roughly as follows: /// ```xml -/// /// /// PATH @@ -38,28 +38,28 @@ /// /// /// ``` - use std::error; use std::fmt; use std::fs::File; use std::io::{Cursor, Write}; -use std::time::{SystemTime, UNIX_EPOCH}; use std::path::{Path, PathBuf}; +use std::time::{SystemTime, UNIX_EPOCH}; -use quick_xml::{Writer, events::{BytesDecl, BytesEnd, BytesStart, Event}}; +use quick_xml::{ + events::{BytesDecl, BytesEnd, BytesStart, Event}, + Writer, +}; use chrono::offset::Utc; -use crate::config::{Config}; +use crate::config::Config; use crate::traces::{CoverageStat, Trace, TraceMap}; - pub fn report(traces: &TraceMap, config: &Config) -> Result<(), Error> { let result = Report::render(config, traces)?; result.export(config) } - #[derive(Debug)] pub enum Error { Unknown, @@ -67,7 +67,6 @@ pub enum Error { } impl error::Error for Error { - #[inline] fn description(&self) -> &str { match self { @@ -82,9 +81,7 @@ impl error::Error for Error { } } - impl fmt::Display for Error { - #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -94,14 +91,13 @@ impl fmt::Display for Error { } } - #[derive(Debug)] pub struct Report { timestamp: i64, lines_covered: usize, lines_valid: usize, line_rate: f64, - branches_covered:usize, + branches_covered: usize, branches_valid: usize, branch_rate: f64, sources: Vec, @@ -109,31 +105,29 @@ pub struct Report { } impl Report { - pub fn render(config: &Config, traces: &TraceMap) -> Result { - let timestamp = Utc::now().timestamp(); - let sources = render_sources(config); - let packages = render_packages(config, traces); - let mut line_rate = 0.0; + let timestamp = Utc::now().timestamp(); + let sources = render_sources(config); + let packages = render_packages(config, traces); + let mut line_rate = 0.0; let mut branch_rate = 0.0; if packages.len() > 0 { - line_rate = packages.iter() - .map(|x| x.line_rate).sum::() / packages.len() as f64; - branch_rate = packages.iter() - .map(|x| x.branch_rate).sum::() / packages.len() as f64; + line_rate = packages.iter().map(|x| x.line_rate).sum::() / packages.len() as f64; + branch_rate = + packages.iter().map(|x| x.branch_rate).sum::() / packages.len() as f64; } Ok(Report { - timestamp: timestamp, + timestamp: timestamp, lines_covered: traces.total_covered(), lines_valid: traces.total_coverable(), - line_rate: line_rate, + line_rate: line_rate, branches_covered: 0, branches_valid: 0, - branch_rate: branch_rate, - sources: sources, - packages: packages, + branch_rate: branch_rate, + sources: sources, + packages: packages, }) } @@ -142,36 +136,42 @@ impl Report { .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))?; let mut writer = Writer::new(Cursor::new(vec![])); - writer.write_event(Event::Decl(BytesDecl::new(b"1.0", None, None))) + writer + .write_event(Event::Decl(BytesDecl::new(b"1.0", None, None))) .map_err(|e| Error::ExportError(e))?; - + let cov_tag = b"coverage"; let mut cov = BytesStart::borrowed(cov_tag, cov_tag.len()); cov.push_attribute(("lines-covered", self.lines_covered.to_string().as_ref())); cov.push_attribute(("lines-valid", self.lines_valid.to_string().as_ref())); cov.push_attribute(("line-rate", self.line_rate.to_string().as_ref())); - cov.push_attribute(("branches-covered", self.branches_covered.to_string().as_ref())); + cov.push_attribute(( + "branches-covered", + self.branches_covered.to_string().as_ref(), + )); cov.push_attribute(("branches-valid", self.branches_valid.to_string().as_ref())); cov.push_attribute(("branch-rate", self.branch_rate.to_string().as_ref())); cov.push_attribute(("complexity", "0")); cov.push_attribute(("version", "1.9")); - + let secs = match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(s) => s.as_secs().to_string(), Err(_) => String::from("0"), }; cov.push_attribute(("timestamp", secs.as_ref())); - - writer.write_event(Event::Start(cov)) + + writer + .write_event(Event::Start(cov)) .map_err(|e| Error::ExportError(e))?; self.export_header(&mut writer) .map_err(|e| Error::ExportError(e))?; - + self.export_packages(&mut writer) .map_err(|e| Error::ExportError(e))?; - writer.write_event(Event::End(BytesEnd::borrowed(cov_tag))) + writer + .write_event(Event::End(BytesEnd::borrowed(cov_tag))) .map_err(|e| Error::ExportError(e))?; let result = writer.into_inner().into_inner(); @@ -182,15 +182,22 @@ impl Report { fn export_header(&self, writer: &mut Writer) -> Result<(), quick_xml::Error> { let sources_tag = b"sources"; let source_tag = b"source"; - writer.write_event(Event::Start(BytesStart::borrowed(sources_tag, sources_tag.len())))?; + writer.write_event(Event::Start(BytesStart::borrowed( + sources_tag, + sources_tag.len(), + )))?; for source in self.sources.iter() { if let Some(ref path) = source.to_str() { - writer.write_event(Event::Start(BytesStart::borrowed(source_tag, source_tag.len())))?; + writer.write_event(Event::Start(BytesStart::borrowed( + source_tag, + source_tag.len(), + )))?; writer.write(path.as_bytes())?; writer.write_event(Event::End(BytesEnd::borrowed(source_tag)))?; } } - writer.write_event(Event::End(BytesEnd::borrowed(sources_tag))) + writer + .write_event(Event::End(BytesEnd::borrowed(sources_tag))) .map(|_| ()) } @@ -198,29 +205,40 @@ impl Report { let packages_tag = b"packages"; let pack_tag = b"package"; - writer.write_event(Event::Start(BytesStart::borrowed(packages_tag, packages_tag.len())))?; + writer.write_event(Event::Start(BytesStart::borrowed( + packages_tag, + packages_tag.len(), + )))?; // Export the package for package in &self.packages { let mut pack = BytesStart::borrowed(pack_tag, pack_tag.len()); pack.push_attribute(("line-rate", package.line_rate.to_string().as_ref())); pack.push_attribute(("branch-rate", package.branch_rate.to_string().as_ref())); pack.push_attribute(("complexity", package.complexity.to_string().as_ref())); - + writer.write_event(Event::Start(pack))?; self.export_classes(&package.classes, writer)?; writer.write_event(Event::End(BytesEnd::borrowed(pack_tag)))?; } - writer.write_event(Event::End(BytesEnd::borrowed(packages_tag))) + writer + .write_event(Event::End(BytesEnd::borrowed(packages_tag))) .map(|_| ()) } - fn export_classes(&self, classes: &[Class], writer: &mut Writer) -> Result<(), quick_xml::Error> { + fn export_classes( + &self, + classes: &[Class], + writer: &mut Writer, + ) -> Result<(), quick_xml::Error> { let classes_tag = b"classes"; let class_tag = b"class"; let methods_tag = b"methods"; - writer.write_event(Event::Start(BytesStart::borrowed(classes_tag, classes_tag.len())))?; + writer.write_event(Event::Start(BytesStart::borrowed( + classes_tag, + classes_tag.len(), + )))?; for class in classes { let mut c = BytesStart::borrowed(class_tag, class_tag.len()); c.push_attribute(("name", class.name.as_ref())); @@ -230,31 +248,46 @@ impl Report { c.push_attribute(("complexity", class.complexity.to_string().as_ref())); writer.write_event(Event::Start(c))?; - writer.write_event(Event::Empty(BytesStart::borrowed(methods_tag, methods_tag.len())))?; + writer.write_event(Event::Empty(BytesStart::borrowed( + methods_tag, + methods_tag.len(), + )))?; self.export_lines(&class.lines, writer)?; writer.write_event(Event::End(BytesEnd::borrowed(class_tag)))?; } - writer.write_event(Event::End(BytesEnd::borrowed(classes_tag))) + writer + .write_event(Event::End(BytesEnd::borrowed(classes_tag))) .map(|_| ()) } - fn export_lines(&self, lines: &[Line], writer: &mut Writer) -> Result<(), quick_xml::Error> { + fn export_lines( + &self, + lines: &[Line], + writer: &mut Writer, + ) -> Result<(), quick_xml::Error> { let lines_tag = b"lines"; let line_tag = b"line"; - writer.write_event(Event::Start(BytesStart::borrowed(lines_tag, lines_tag.len())))?; + writer.write_event(Event::Start(BytesStart::borrowed( + lines_tag, + lines_tag.len(), + )))?; for line in lines { let mut l = BytesStart::borrowed(line_tag, line_tag.len()); match line { - Line::Plain{ref number, ref hits} => { + Line::Plain { + ref number, + ref hits, + } => { l.push_attribute(("number", number.to_string().as_ref())); l.push_attribute(("hits", hits.to_string().as_ref())); - }, - Line::Branch{..} => {}, + } + Line::Branch { .. } => {} } writer.write_event(Event::Empty(l))?; } - writer.write_event(Event::End(BytesEnd::borrowed(lines_tag))) + writer + .write_event(Event::End(BytesEnd::borrowed(lines_tag))) .map(|_| ()) } } @@ -267,16 +300,17 @@ fn render_sources(config: &Config) -> Vec { #[derive(Debug)] struct Package { - name: String, - line_rate: f64, - branch_rate: f64, - complexity: f64, - classes: Vec, + name: String, + line_rate: f64, + branch_rate: f64, + complexity: f64, + classes: Vec, } - fn render_packages(config: &Config, traces: &TraceMap) -> Vec { - let mut dirs: Vec<&Path> = traces.files().into_iter() + let mut dirs: Vec<&Path> = traces + .files() + .into_iter() .filter_map(|x| x.parent()) .collect(); @@ -287,10 +321,10 @@ fn render_packages(config: &Config, traces: &TraceMap) -> Vec { .collect() } - fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package { let root = config.manifest.parent().unwrap_or(&config.manifest); - let name = pkg.strip_prefix(root) + let name = pkg + .strip_prefix(root) .map(|x| Path::to_str(x)) .unwrap_or_default() .unwrap_or_default(); @@ -299,28 +333,29 @@ fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package { let line_rate = line_cover / (traces.coverable_in_path(pkg) as f64); Package { - name: name.to_string(), - line_rate: line_rate, - branch_rate: 0.0, - complexity: 0.0, - classes: render_classes(config, traces, pkg) + name: name.to_string(), + line_rate: line_rate, + branch_rate: 0.0, + complexity: 0.0, + classes: render_classes(config, traces, pkg), } } - #[derive(Debug)] struct Class { - name: String, - file_name: String, - line_rate: f64, - branch_rate: f64, - complexity: f64, - lines: Vec, - methods: Vec, + name: String, + file_name: String, + line_rate: f64, + branch_rate: f64, + complexity: f64, + lines: Vec, + methods: Vec, } fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec { - traces.files().iter() + traces + .files() + .iter() .filter(|x| x.parent() == Some(pkg)) .map(|x| render_class(config, traces, x)) .collect() @@ -336,12 +371,14 @@ fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec // fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class { let root = config.manifest.parent().unwrap_or(&config.manifest); - let name = file.file_stem() + let name = file + .file_stem() .map(|x| x.to_str().unwrap()) .unwrap_or_default() .to_string(); - let file_name = file.strip_prefix(root) + let file_name = file + .strip_prefix(root) .unwrap_or(file) .to_str() .unwrap() @@ -349,29 +386,30 @@ fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class { let covered = traces.covered_in_path(file) as f64; let line_rate = covered / traces.coverable_in_path(file) as f64; - let lines = traces.get_child_traces(file).iter() + let lines = traces + .get_child_traces(file) + .iter() .map(|x| render_line(x)) .collect(); Class { - name: name, - file_name: file_name, - line_rate: line_rate, - branch_rate: 0.0, - complexity: 0.0, - lines: lines, - methods: vec![] + name: name, + file_name: file_name, + line_rate: line_rate, + branch_rate: 0.0, + complexity: 0.0, + lines: lines, + methods: vec![], } } - #[derive(Debug)] struct Method { - name: String, - signature: String, - line_rate: f64, - branch_rate: f64, - lines: Vec, + name: String, + signature: String, + line_rate: f64, + branch_rate: f64, + lines: Vec, } fn render_methods() -> Vec { @@ -382,47 +420,43 @@ fn render_method() -> Method { unimplemented!() } - #[derive(Debug)] enum Line { Plain { - number: usize, - hits: usize, + number: usize, + hits: usize, }, Branch { - number: usize, - hits: usize, + number: usize, + hits: usize, conditions: Vec, - } + }, } fn render_line(trace: &Trace) -> Line { match &trace.stats { CoverageStat::Line(hits) => Line::Plain { number: trace.line as usize, - hits: *hits as usize + hits: *hits as usize, }, // TODO: Branches in cobertura are given a fresh number as a label, // which would require having some form of context when rendering. // - _ => panic!("Not currently supported") + _ => panic!("Not currently supported"), } } - #[derive(Debug)] struct Condition { - number: usize, - cond_type: ConditionType, - coverage: f64, + number: usize, + cond_type: ConditionType, + coverage: f64, } - // Condition types #[derive(Debug)] enum ConditionType { Jump, } - diff --git a/src/report/coveralls.rs b/src/report/coveralls.rs index a77bddafcb..801ee5b68c 100644 --- a/src/report/coveralls.rs +++ b/src/report/coveralls.rs @@ -2,11 +2,10 @@ use crate::config::Config; use crate::errors::RunError; use crate::traces::{CoverageStat, TraceMap}; use coveralls_api::*; -use log::{info, warn, trace}; +use log::{info, trace, warn}; use std::collections::HashMap; -use std::path::Path; use std::fs; - +use std::path::Path; fn get_git_info(manifest_path: &Path) -> Result { let dir_path = manifest_path @@ -54,7 +53,6 @@ fn get_git_info(manifest_path: &Path) -> Result { }) } - fn get_identity(ci_tool: &Option, key: &str) -> Identity { match ci_tool { Some(ref service) => { @@ -67,7 +65,7 @@ fn get_identity(ci_tool: &Option, key: &str) -> Identity { build_url: None, branch: None, pull_request: None, - } + }, }; let key = if service == &CiService::Travis { String::new() @@ -75,12 +73,11 @@ fn get_identity(ci_tool: &Option, key: &str) -> Identity { key.to_string() }; Identity::ServiceToken(key, service_object) - }, + } _ => Identity::best_match_with_token(key.to_string()), } } - pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> { if let Some(ref key) = config.coveralls { let id = get_identity(&config.ci_tool, key); @@ -136,7 +133,7 @@ pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> Ok(s) => { trace!("Coveralls response {:?}", s); Ok(()) - }, + } Err(e) => Err(RunError::CovReport(format!("Coveralls send failed. {}", e))), } } else { diff --git a/src/source_analysis.rs b/src/source_analysis.rs index 6dbc3a1fdc..930ed076da 100644 --- a/src/source_analysis.rs +++ b/src/source_analysis.rs @@ -626,7 +626,6 @@ fn visit_block(block: &Block, ctx: &Context, analysis: &mut LineAnalysis) -> Sub } fn visit_closure(closure: &ExprClosure, ctx: &Context, analysis: &mut LineAnalysis) -> SubResult { - process_expr(&closure.body, ctx, analysis); // Even if a closure is "unreachable" it might be part of a chained method // call and I don't want that propagating up. diff --git a/src/statemachine.rs b/src/statemachine.rs index 6d05475c48..f4ce703683 100644 --- a/src/statemachine.rs +++ b/src/statemachine.rs @@ -3,7 +3,7 @@ use crate::config::Config; use crate::errors::RunError; use crate::ptrace_control::*; use crate::traces::*; -use log::{debug, warn, trace}; +use log::{debug, trace, warn}; use nix::errno::Errno; use nix::sys::signal::Signal; use nix::sys::wait::*; @@ -238,21 +238,20 @@ impl<'a> StateData for LinuxData<'a> { ))), } } - WaitStatus::Stopped(child, Signal::SIGSTOP) => { - match continue_exec(child, None) { - Ok(_) => Ok(TestState::wait_state()), - Err(e) => Err(RunError::TestRuntime(format!( - "Error processing SIGSTOP: {}", - e.to_string() - ))), - } + WaitStatus::Stopped(child, Signal::SIGSTOP) => match continue_exec(child, None) { + Ok(_) => Ok(TestState::wait_state()), + Err(e) => Err(RunError::TestRuntime(format!( + "Error processing SIGSTOP: {}", + e.to_string() + ))), }, WaitStatus::Stopped(_, Signal::SIGSEGV) => Err(RunError::TestRuntime( "A segfault occurred while executing tests".to_string(), )), - WaitStatus::Stopped(child, Signal::SIGILL) => { - Err(RunError::TestRuntime(format!("Error running test - SIGILL raised in {}", child))) - }, + WaitStatus::Stopped(child, Signal::SIGILL) => Err(RunError::TestRuntime(format!( + "Error running test - SIGILL raised in {}", + child + ))), WaitStatus::Stopped(c, s) => { let sig = if self.config.forward_signals { Some(s) @@ -314,22 +313,20 @@ impl<'a> LinuxData<'a> { if sig == Signal::SIGTRAP { match event { - PTRACE_EVENT_CLONE => { - match get_event_data(child) { - Ok(t) => { - trace!("New thread spawned {}", t); - self.thread_count += 1; - continue_exec(child, None)?; - Ok(TestState::wait_state()) - }, - Err(e) => { - trace!("Error in clone event {:?}", e); - Err(RunError::TestRuntime( - "Error occurred upon test executable thread creation".to_string(), - )) - } + PTRACE_EVENT_CLONE => match get_event_data(child) { + Ok(t) => { + trace!("New thread spawned {}", t); + self.thread_count += 1; + continue_exec(child, None)?; + Ok(TestState::wait_state()) } - } + Err(e) => { + trace!("Error in clone event {:?}", e); + Err(RunError::TestRuntime( + "Error occurred upon test executable thread creation".to_string(), + )) + } + }, PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK => { trace!("Caught fork event"); continue_exec(child, None)?; diff --git a/src/test_loader.rs b/src/test_loader.rs index 7947faea85..a9213357d5 100644 --- a/src/test_loader.rs +++ b/src/test_loader.rs @@ -275,8 +275,17 @@ fn get_line_addresses( for v in val.iter() { let rpath = config.strip_project_path(&k.path); match v.address { - Some(ref a) => trace!("Adding trace at address 0x{:x} in {}:{}", a, rpath.display(), k.line), - None => trace!("Adding trace with no address at {}:{}", rpath.display(), k.line), + Some(ref a) => trace!( + "Adding trace at address 0x{:x} in {}:{}", + a, + rpath.display(), + k.line + ), + None => trace!( + "Adding trace with no address at {}:{}", + rpath.display(), + k.line + ), } tracemap.add_trace( &k.path, @@ -303,7 +312,11 @@ fn get_line_addresses( if !result.contains_location(file, line) && !line_analysis.should_ignore(line as usize) { let rpath = config.strip_project_path(file); - trace!("Adding trace for potentially uncoverable line in {}:{}", rpath.display(), line); + trace!( + "Adding trace for potentially uncoverable line in {}:{}", + rpath.display(), + line + ); result.add_trace( file, Trace { @@ -330,12 +343,14 @@ fn open_symbols_file(test: &Path) -> io::Result { File::open(&d_sym) } -pub fn generate_tracemap(project: &Workspace, test: &Path, config: &Config) -> io::Result { +pub fn generate_tracemap( + project: &Workspace, + test: &Path, + config: &Config, +) -> io::Result { let manifest = project.root(); let file = open_symbols_file(test)?; - let file = unsafe { - MmapOptions::new().map(&file)? - }; + let file = unsafe { MmapOptions::new().map(&file)? }; if let Ok(obj) = OFile::parse(&*file) { let analysis = get_line_analysis(project, config); let endian = if obj.is_little_endian() { diff --git a/tests/line_coverage.rs b/tests/line_coverage.rs index ee7a8d78e7..111ca96359 100644 --- a/tests/line_coverage.rs +++ b/tests/line_coverage.rs @@ -46,5 +46,4 @@ fn simple_project_coverage() { assert_eq!(CoverageStat::Line(1), l.stats); } } - }