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