Skip to content

Commit 40654ba

Browse files
elopezanishnaik
andauthored
Add coverage report filtering option (#663)
This option takes a list of globs and removes those files from coverage reports. Example: `["lib/**/*", "test/**/*"]` Closes: #644 Co-authored-by: Anish Naik <[email protected]>
1 parent ca794b1 commit 40654ba

File tree

6 files changed

+65
-4
lines changed

6 files changed

+65
-4
lines changed

fuzzing/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ type FuzzingConfig struct {
7070
// CoverageFormats indicate which reports to generate: "lcov" and "html" are supported.
7171
CoverageFormats []string `json:"coverageFormats"`
7272

73+
// CoverageExclusions defines file/directory patterns to exclude from coverage reports.
74+
// Supports glob patterns like "lib/**", "test/helpers/**", "*.generated.sol"
75+
CoverageExclusions []string `json:"coverageExclusions"`
76+
7377
// RevertReporterEnabled determines whether revert metrics should be collected and reported.
7478
RevertReporterEnabled bool `json:"revertReporterEnabled"`
7579

fuzzing/config/config_defaults.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func GetDefaultProjectConfig(platform string) (*ProjectConfig, error) {
5353
CorpusDirectory: "",
5454
CoverageEnabled: true,
5555
CoverageFormats: []string{"html", "lcov"},
56+
CoverageExclusions: []string{},
5657
SenderAddresses: []string{
5758
"0x10000",
5859
"0x20000",

fuzzing/coverage/source_analysis.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import (
44
"bytes"
55
"encoding/json"
66
"fmt"
7+
"os"
8+
"path/filepath"
79
"sort"
810

11+
"github.com/bmatcuk/doublestar/v4"
912
"github.com/crytic/medusa-geth/core/vm"
1013
"github.com/crytic/medusa/compilation/types"
1114
"github.com/crytic/medusa/logging"
@@ -58,6 +61,52 @@ func (s *SourceAnalysis) CoveredLineCount() int {
5861
return count
5962
}
6063

64+
// shouldExcludeFile checks if a file path matches any of the exclusion patterns
65+
func shouldExcludeFile(filePath string, exclusionPatterns []string) bool {
66+
for _, pattern := range exclusionPatterns {
67+
if matched, err := doublestar.Match(pattern, filePath); err == nil && matched {
68+
return true
69+
}
70+
}
71+
return false
72+
}
73+
74+
// filterExcludedFiles removes files matching exclusion patterns from the source analysis.
75+
// Pattern matching is performed on relative paths (relative to current working directory)
76+
// to match the behavior of the coverage report display.
77+
func (s *SourceAnalysis) filterExcludedFiles(exclusionPatterns []string) {
78+
if len(exclusionPatterns) == 0 {
79+
return
80+
}
81+
82+
// Get current working directory to convert absolute paths to relative paths
83+
// This ensures pattern matching works on the same relative paths shown in reports
84+
cwd, err := os.Getwd()
85+
if err != nil {
86+
// If we can't get the working directory, skip filtering to avoid issues
87+
return
88+
}
89+
90+
// Create a new map without excluded files
91+
filteredFiles := make(map[string]*SourceFileAnalysis)
92+
93+
for filePath, fileAnalysis := range s.Files {
94+
// Convert to relative path for pattern matching (same logic as in report template)
95+
relativePath := filePath
96+
if relPath, err := filepath.Rel(cwd, filePath); err == nil {
97+
relativePath = relPath
98+
}
99+
100+
// Keep the file if it doesn't match any exclusion pattern
101+
if !shouldExcludeFile(relativePath, exclusionPatterns) {
102+
filteredFiles[filePath] = fileAnalysis
103+
}
104+
}
105+
106+
// Replace the original files map with filtered results
107+
s.Files = filteredFiles
108+
}
109+
61110
// GenerateLCOVReport generates an LCOV report from the source analysis.
62111
// The spec of the format is here https://github.com/linux-test-project/lcov/blob/07a1127c2b4390abf4a516e9763fb28a956a9ce4/man/geninfo.1#L989
63112
func (s *SourceAnalysis) GenerateLCOVReport() string {
@@ -214,10 +263,10 @@ func GetUniquePCsCount(compilations []types.Compilation, coverageMaps *CoverageM
214263
return uniquePCs, nil
215264
}
216265

217-
// AnalyzeSourceCoverage takes a list of compilations and a set of coverage maps, and performs source analysis
218-
// to determine source coverage information.
266+
// AnalyzeSourceCoverage takes a list of compilations, coverage maps, and exclusion patterns, then performs source analysis
267+
// to determine source coverage information. Files matching the exclusion patterns will be filtered out from the results.
219268
// Returns a SourceAnalysis object, or an error if one occurs.
220-
func AnalyzeSourceCoverage(compilations []types.Compilation, coverageMaps *CoverageMaps, logger *logging.Logger) (*SourceAnalysis, error) {
269+
func AnalyzeSourceCoverage(compilations []types.Compilation, coverageMaps *CoverageMaps, exclusionPatterns []string, logger *logging.Logger) (*SourceAnalysis, error) {
221270
// Create a new source analysis object
222271
sourceAnalysis := &SourceAnalysis{
223272
Files: make(map[string]*SourceFileAnalysis),
@@ -323,6 +372,10 @@ func AnalyzeSourceCoverage(compilations []types.Compilation, coverageMaps *Cover
323372
}
324373
}
325374
}
375+
376+
// Apply exclusion filtering if patterns are provided
377+
sourceAnalysis.filterExcludedFiles(exclusionPatterns)
378+
326379
return sourceAnalysis, nil
327380
}
328381

fuzzing/fuzzer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ func (f *Fuzzer) Start() error {
10221022
if f.config.Fuzzing.CorpusDirectory != "" {
10231023
coverageReportDir = filepath.Join(f.config.Fuzzing.CorpusDirectory, "coverage")
10241024
}
1025-
sourceAnalysis, err := coverage.AnalyzeSourceCoverage(f.compilations, f.corpus.CoverageMaps(), f.logger)
1025+
sourceAnalysis, err := coverage.AnalyzeSourceCoverage(f.compilations, f.corpus.CoverageMaps(), f.config.Fuzzing.CoverageExclusions, f.logger)
10261026

10271027
if err != nil {
10281028
f.logger.Error("Failed to analyze source coverage", err)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ toolchain go1.23.3
66

77
require (
88
github.com/Masterminds/semver v1.5.0
9+
github.com/bmatcuk/doublestar/v4 v4.9.1
910
github.com/crytic/medusa-geth v0.0.0-20250423141023-d818338d6925
1011
github.com/fxamacker/cbor v1.5.1
1112
github.com/google/uuid v1.6.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
1212
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
1313
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
1414
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
15+
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
16+
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
1517
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1618
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
1719
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=

0 commit comments

Comments
 (0)