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