1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Support for test coverage.
6
7package testing
8
9import (
10	"fmt"
11	"internal/goexperiment"
12	"os"
13	"sync/atomic"
14)
15
16// CoverBlock records the coverage data for a single basic block.
17// The fields are 1-indexed, as in an editor: The opening line of
18// the file is number 1, for example. Columns are measured
19// in bytes.
20// NOTE: This struct is internal to the testing infrastructure and may change.
21// It is not covered (yet) by the Go 1 compatibility guidelines.
22type CoverBlock struct {
23	Line0 uint32 // Line number for block start.
24	Col0  uint16 // Column number for block start.
25	Line1 uint32 // Line number for block end.
26	Col1  uint16 // Column number for block end.
27	Stmts uint16 // Number of statements included in this block.
28}
29
30var cover Cover
31
32// Cover records information about test coverage checking.
33// NOTE: This struct is internal to the testing infrastructure and may change.
34// It is not covered (yet) by the Go 1 compatibility guidelines.
35type Cover struct {
36	Mode            string
37	Counters        map[string][]uint32
38	Blocks          map[string][]CoverBlock
39	CoveredPackages string
40}
41
42// Coverage reports the current code coverage as a fraction in the range [0, 1].
43// If coverage is not enabled, Coverage returns 0.
44//
45// When running a large set of sequential test cases, checking Coverage after each one
46// can be useful for identifying which test cases exercise new code paths.
47// It is not a replacement for the reports generated by 'go test -cover' and
48// 'go tool cover'.
49func Coverage() float64 {
50	if goexperiment.CoverageRedesign {
51		return coverage2()
52	}
53	var n, d int64
54	for _, counters := range cover.Counters {
55		for i := range counters {
56			if atomic.LoadUint32(&counters[i]) > 0 {
57				n++
58			}
59			d++
60		}
61	}
62	if d == 0 {
63		return 0
64	}
65	return float64(n) / float64(d)
66}
67
68// RegisterCover records the coverage data accumulators for the tests.
69// NOTE: This function is internal to the testing infrastructure and may change.
70// It is not covered (yet) by the Go 1 compatibility guidelines.
71func RegisterCover(c Cover) {
72	cover = c
73}
74
75// mustBeNil checks the error and, if present, reports it and exits.
76func mustBeNil(err error) {
77	if err != nil {
78		fmt.Fprintf(os.Stderr, "testing: %s\n", err)
79		os.Exit(2)
80	}
81}
82
83// coverReport reports the coverage percentage and writes a coverage profile if requested.
84func coverReport() {
85	if goexperiment.CoverageRedesign {
86		coverReport2()
87		return
88	}
89	var f *os.File
90	var err error
91	if *coverProfile != "" {
92		f, err = os.Create(toOutputDir(*coverProfile))
93		mustBeNil(err)
94		fmt.Fprintf(f, "mode: %s\n", cover.Mode)
95		defer func() { mustBeNil(f.Close()) }()
96	}
97
98	var active, total int64
99	var count uint32
100	for name, counts := range cover.Counters {
101		blocks := cover.Blocks[name]
102		for i := range counts {
103			stmts := int64(blocks[i].Stmts)
104			total += stmts
105			count = atomic.LoadUint32(&counts[i]) // For -mode=atomic.
106			if count > 0 {
107				active += stmts
108			}
109			if f != nil {
110				_, err := fmt.Fprintf(f, "%s:%d.%d,%d.%d %d %d\n", name,
111					blocks[i].Line0, blocks[i].Col0,
112					blocks[i].Line1, blocks[i].Col1,
113					stmts,
114					count)
115				mustBeNil(err)
116			}
117		}
118	}
119	if total == 0 {
120		fmt.Println("coverage: [no statements]")
121		return
122	}
123	fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages)
124}
125