Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(coverage): better branch handling #2133

Merged
merged 11 commits into from Jun 28, 2022
45 changes: 37 additions & 8 deletions cli/src/cmd/forge/coverage.rs
Expand Up @@ -10,7 +10,7 @@ use crate::{
use cast::trace::identifier::TraceIdentifier;
use clap::{AppSettings, ArgEnum, Parser};
use ethers::{
prelude::{Artifact, Project, ProjectCompileOutput},
prelude::{Artifact, Bytes, Project, ProjectCompileOutput},
solc::{artifacts::contract::CompactContractBytecode, sourcemap::SourceMap, ArtifactId},
};
use forge::{
Expand Down Expand Up @@ -119,15 +119,19 @@ impl CoverageArgs {

/// Builds the coverage map.
fn prepare(&self, output: ProjectCompileOutput) -> eyre::Result<(CoverageMap, SourceMaps)> {
// Get sources and source maps
// Extract artifacts
let (artifacts, sources) = output.into_artifacts_with_sources();

let source_maps: SourceMaps = artifacts
let artifacts: HashMap<ArtifactId, CompactContractBytecode> = artifacts
.into_iter()
.map(|(id, artifact)| (id, CompactContractBytecode::from(artifact)))
.filter_map(|(id, artifact): (ArtifactId, CompactContractBytecode)| {
.collect();

// Get source maps
let source_maps: SourceMaps = artifacts
.iter()
.filter_map(|(id, artifact)| {
Some((
id,
id.clone(),
(
artifact.get_source_map()?.ok()?,
artifact
Expand All @@ -142,6 +146,20 @@ impl CoverageArgs {
})
.collect();

// Get bytecodes
let bytecodes: HashMap<ArtifactId, (Bytes, Bytes)> = artifacts
.iter()
.filter_map(|(id, artifact)| {
Some((
id.clone(),
(
artifact.get_bytecode_bytes()?.into_owned(),
artifact.get_deployed_bytecode_bytes()?.into_owned(),
),
))
})
.collect();

let mut map = CoverageMap::default();
for (path, versioned_sources) in sources.0.into_iter() {
// TODO: Make these checks robust
Expand All @@ -165,12 +183,23 @@ impl CoverageArgs {
id.source == PathBuf::from(&path)
})
.map(|(id, (_, source_map))| {
// TODO: Deploy source map too?
// TODO: Deploy source map too
(id.name.clone(), source_map.clone())
})
.collect();
let bytecodes: HashMap<String, Bytes> = bytecodes
.iter()
.filter(|(id, _)| {
id.version == versioned_source.version &&
id.source == PathBuf::from(&path)
})
.map(|(id, (_, bytecode))| {
// TODO: Deploy bytecode too
(id.name.clone(), bytecode.clone())
})
.collect();

let items = Visitor::new(source.id, fs::read_to_string(&path)?, source_maps)
let items = Visitor::new(fs::read_to_string(&path)?, source_maps, bytecodes)
.visit_ast(ast)?;

if items.is_empty() {
Expand Down
17 changes: 2 additions & 15 deletions evm/src/coverage/mod.rs
Expand Up @@ -213,8 +213,6 @@ pub enum CoverageItem {
///
/// The first path has ID 0, the next ID 1, and so on.
path_id: usize,
/// The branch kind.
kind: BranchKind,
/// The number of times this item was hit.
hits: u64,
},
Expand Down Expand Up @@ -279,11 +277,8 @@ impl Display for CoverageItem {
CoverageItem::Statement { loc, anchor, hits } => {
write!(f, "Statement (location: {loc}, anchor: {anchor}, hits: {hits})")
}
CoverageItem::Branch { loc, anchor, hits, branch_id, path_id, kind } => {
write!(f, "{} Branch (branch: {branch_id}, path: {path_id}) (location: {loc}, anchor: {anchor}, hits: {hits})", match kind {
BranchKind::True => "True",
BranchKind::False => "False",
})
CoverageItem::Branch { loc, anchor, hits, branch_id, path_id } => {
write!(f, "Branch (branch: {branch_id}, path: {path_id}) (location: {loc}, anchor: {anchor}, hits: {hits})")
}
CoverageItem::Function { loc, anchor, hits, name } => {
write!(f, r#"Function "{name}" (location: {loc}, anchor: {anchor}, hits: {hits})"#)
Expand Down Expand Up @@ -314,14 +309,6 @@ impl Display for SourceLocation {
}
}

#[derive(Debug, Clone)]
pub enum BranchKind {
/// A false branch
True,
/// A true branch
False,
}

/// Coverage summary for a source file.
#[derive(Default, Debug, Clone)]
pub struct CoverageSummary {
Expand Down