aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-04-10 12:01:26 +0200
committerDmitry Vyukov <dvyukov@google.com>2025-04-10 10:35:55 +0000
commite63481ffe5d7a5688b7422c02445312b5e9046eb (patch)
treeba4459b857101e9585ae0dca8d23d197d54131f7
parent61f3a7a57df08628edf27581563a6b1c9afb61a2 (diff)
dashboard/app: export info about uncovered blocks as well
Currently it's only possible to understand total number of uncovered blocks in a function (implicitly defined by Instrumented field). This does not allow to render coverage data, nor do detailed analysis on line level. Export detailed info about both covered and uncovered blocks. This allows to e.g. calculate coverage percent for kernel interfaces.
-rw-r--r--dashboard/app/public_json_api.go39
-rw-r--r--dashboard/app/public_json_api_test.go18
-rw-r--r--pkg/cover/html.go27
-rw-r--r--pkg/cover/report_test.go4
4 files changed, 42 insertions, 46 deletions
diff --git a/dashboard/app/public_json_api.go b/dashboard/app/public_json_api.go
index aa99b41a8..90e2fe8d6 100644
--- a/dashboard/app/public_json_api.go
+++ b/dashboard/app/public_json_api.go
@@ -232,42 +232,29 @@ func writeFileCoverage(ctx context.Context, w io.Writer, repo string, ff *covera
}
func genFuncsCov(fc *coveragedb.FileCoverageWithLineInfo, ff *coveragedb.FunctionFinder,
-) ([]*cover.FunctionCoverage, error) {
- nameToLines := map[string][]int{}
- funcInstrumented := map[string]int{}
+) ([]*cover.FuncCoverage, error) {
+ nameToLines := map[string][]*cover.Block{}
for i, hitCount := range fc.HitCounts {
lineNum := int(fc.LinesInstrumented[i])
funcName, err := ff.FileLineToFuncName(fc.Filepath, lineNum)
if err != nil {
return nil, fmt.Errorf("ff.FileLineToFuncName: %w", err)
}
- funcInstrumented[funcName]++
- if hitCount == 0 {
- continue
- }
- nameToLines[funcName] = append(nameToLines[funcName], lineNum)
- }
-
- var res []*cover.FunctionCoverage
- for funcName, lines := range nameToLines {
- res = append(res, &cover.FunctionCoverage{
- FuncName: funcName,
- Instrumented: funcInstrumented[funcName],
- Blocks: linesToBlocks(lines),
- })
- }
- return res, nil
-}
-
-func linesToBlocks(lines []int) []*cover.CoveredBlock {
- var res []*cover.CoveredBlock
- for _, lineNum := range lines {
- res = append(res, &cover.CoveredBlock{
+ nameToLines[funcName] = append(nameToLines[funcName], &cover.Block{
+ HitCount: int(hitCount),
FromLine: lineNum,
FromCol: 0,
ToLine: lineNum,
ToCol: -1,
})
}
- return res
+
+ var res []*cover.FuncCoverage
+ for funcName, blocks := range nameToLines {
+ res = append(res, &cover.FuncCoverage{
+ FuncName: funcName,
+ Blocks: blocks,
+ })
+ }
+ return res, nil
}
diff --git a/dashboard/app/public_json_api_test.go b/dashboard/app/public_json_api_test.go
index de51bd3b7..f0aee9f79 100644
--- a/dashboard/app/public_json_api_test.go
+++ b/dashboard/app/public_json_api_test.go
@@ -264,7 +264,7 @@ func TestWriteExtAPICoverageFor(t *testing.T) {
{
FilePath: "/file",
FuncName: "func_name",
- Lines: []int64{1, 2, 3},
+ Lines: []int64{1, 2, 3, 4},
},
},
[]*coveragedb.FileCoverageWithLineInfo{
@@ -273,8 +273,8 @@ func TestWriteExtAPICoverageFor(t *testing.T) {
Filepath: "/file",
Commit: "test-commit",
},
- LinesInstrumented: []int64{1, 2, 3},
- HitCounts: []int64{10, 20, 30},
+ LinesInstrumented: []int64{1, 2, 3, 4},
+ HitCounts: []int64{10, 20, 30, 0},
},
},
))
@@ -289,25 +289,33 @@ func TestWriteExtAPICoverageFor(t *testing.T) {
"functions": [
{
"func_name": "func_name",
- "total_blocks": 3,
- "covered_blocks": [
+ "blocks": [
{
+ "hit_count": 10,
"from_line": 1,
"from_column": 0,
"to_line": 1,
"to_column": -1
},
{
+ "hit_count": 20,
"from_line": 2,
"from_column": 0,
"to_line": 2,
"to_column": -1
},
{
+ "hit_count": 30,
"from_line": 3,
"from_column": 0,
"to_line": 3,
"to_column": -1
+ },
+ {
+ "from_line": 4,
+ "from_column": 0,
+ "to_line": 4,
+ "to_column": -1
}
]
}
diff --git a/pkg/cover/html.go b/pkg/cover/html.go
index c7bd945b6..1b2d4d024 100644
--- a/pkg/cover/html.go
+++ b/pkg/cover/html.go
@@ -264,19 +264,19 @@ type ProgramCoverage struct {
}
type FileCoverage struct {
- Repo string `json:"repo,omitempty"`
- Commit string `json:"commit,omitempty"`
- FilePath string `json:"file_path"`
- Functions []*FunctionCoverage `json:"functions"`
+ Repo string `json:"repo,omitempty"`
+ Commit string `json:"commit,omitempty"`
+ FilePath string `json:"file_path"`
+ Functions []*FuncCoverage `json:"functions"`
}
-type FunctionCoverage struct {
- FuncName string `json:"func_name"`
- Instrumented int `json:"total_blocks,omitempty"`
- Blocks []*CoveredBlock `json:"covered_blocks"`
+type FuncCoverage struct {
+ FuncName string `json:"func_name"`
+ Blocks []*Block `json:"blocks"`
}
-type CoveredBlock struct {
+type Block struct {
+ HitCount int `json:"hit_count,omitempty"`
FromLine int `json:"from_line"`
FromCol int `json:"from_column"`
ToLine int `json:"to_line"`
@@ -312,22 +312,23 @@ func (rg *ReportGenerator) DoCoverPrograms(w io.Writer, params HandlerParams) er
var progCoverage []*FileCoverage
for filePath, functions := range fileFuncFrames {
- var expFuncs []*FunctionCoverage
+ var expFuncs []*FuncCoverage
for funcName, frames := range functions {
- var expCoveredBlocks []*CoveredBlock
+ var expCoveredBlocks []*Block
for _, frame := range frames {
endCol := frame.EndCol
if endCol == backend.LineEnd {
endCol = -1
}
- expCoveredBlocks = append(expCoveredBlocks, &CoveredBlock{
+ expCoveredBlocks = append(expCoveredBlocks, &Block{
+ HitCount: 1,
FromCol: frame.StartCol,
FromLine: frame.StartLine,
ToCol: endCol,
ToLine: frame.EndLine,
})
}
- expFuncs = append(expFuncs, &FunctionCoverage{
+ expFuncs = append(expFuncs, &FuncCoverage{
FuncName: funcName,
Blocks: expCoveredBlocks,
})
diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go
index 002ff1958..96b634cc6 100644
--- a/pkg/cover/report_test.go
+++ b/pkg/cover/report_test.go
@@ -424,7 +424,6 @@ func checkCSVReport(t *testing.T, CSVReport []byte) {
}
}
-// nolint:lll
func checkJSONLReport(t *testing.T, gotBytes, wantBytes []byte) {
compacted := new(bytes.Buffer)
if err := json.Compact(compacted, wantBytes); err != nil {
@@ -446,8 +445,9 @@ var sampleJSONLlProgs = []byte(`{
"functions": [
{
"func_name": "main",
- "covered_blocks": [
+ "blocks": [
{
+ "hit_count": 1,
"from_line": 1,
"from_column": 0,
"to_line": 1,