code-intelligence.com/cifuzz@v0.40.0/internal/cmd/coverage/summary/lcov.go (about) 1 package summary 2 3 import ( 4 "bufio" 5 "encoding/json" 6 "io" 7 "strconv" 8 "strings" 9 10 "code-intelligence.com/cifuzz/pkg/log" 11 ) 12 13 func count(c *Coverage, key string, value int) { 14 switch key { 15 case "FNF": 16 c.FunctionsFound += value 17 case "FNH": 18 c.FunctionsHit += value 19 case "BRF": 20 c.BranchesFound += value 21 case "BRH": 22 c.BranchesHit += value 23 case "LF": 24 c.LinesFound += value 25 case "LH": 26 c.LinesHit += value 27 } 28 } 29 30 // ParseLcov takes a lcov tracefile report and turns it into 31 // the `CoverageSummary` struct. The parsing is as forgiving 32 // as possible. It will output debug/error logs instead of 33 // failing, with the goal to gather as much information as 34 // possible 35 func ParseLcov(in io.Reader) *CoverageSummary { 36 summary := &CoverageSummary{ 37 Total: &Coverage{}, 38 } 39 40 var currentFile *FileCoverage 41 42 // The definition of the lcov tracefile format can be viewed 43 // with `man geninfo` 44 scanner := bufio.NewScanner(in) 45 for scanner.Scan() { 46 parts := strings.SplitN(scanner.Text(), ":", 2) 47 key := parts[0] 48 49 switch key { 50 51 // SF starts a section (for a single file) 52 case "SF": 53 currentFile = &FileCoverage{ 54 Filename: parts[1], 55 Coverage: &Coverage{}, 56 } 57 summary.Files = append(summary.Files, currentFile) 58 59 // end of a section 60 case "end_of_record": 61 currentFile = nil 62 63 // high level coverage metrics 64 case "FNF", "FNH", "BRF", "BRH", "LF", "LH": 65 if len(parts) == 1 { 66 log.Debugf("Parsing lcov: no value for key '%s'", key) 67 break 68 } 69 70 value, err := strconv.Atoi(parts[1]) 71 if err != nil { 72 log.Errorf(err, "Parsing lcov: unable to convert value %s to int", parts[1]) 73 value = 0 74 } 75 76 count(summary.Total, key, value) 77 if currentFile != nil { 78 count(currentFile.Coverage, key, value) 79 } 80 81 // these keys are (currently) not relevant for cifuzz 82 // so we just ignore them 83 case "TN", "FN", "FNDA", "BRDA", "DA": 84 log.Debugf("Parsing lcov: Ignored key '%s'. Not implemented by now. ", key) 85 86 // this branch should only be reached if a key shows up 87 // that is not defined in the format specification 88 default: 89 log.Debugf("Parsing lcov: Unknown key '%s'", key) 90 91 } 92 } 93 94 out, err := json.MarshalIndent(summary, "", " ") 95 if err != nil { 96 log.Error(err, "Parsing lcov: Unable to convert coverage summary to json") 97 } else { 98 log.Debugf("Successfully parsed lcov report : %s", string(out)) 99 } 100 101 return summary 102 }