github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/testing/cover.go (about) 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 "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. 22 type 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 30 var 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. 35 type 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'. 49 func Coverage() float64 { 50 var n, d int64 51 for _, counters := range cover.Counters { 52 for i := range counters { 53 if atomic.LoadUint32(&counters[i]) > 0 { 54 n++ 55 } 56 d++ 57 } 58 } 59 if d == 0 { 60 return 0 61 } 62 return float64(n) / float64(d) 63 } 64 65 // RegisterCover records the coverage data accumulators for the tests. 66 // NOTE: This function is internal to the testing infrastructure and may change. 67 // It is not covered (yet) by the Go 1 compatibility guidelines. 68 func RegisterCover(c Cover) { 69 cover = c 70 } 71 72 // mustBeNil checks the error and, if present, reports it and exits. 73 func mustBeNil(err error) { 74 if err != nil { 75 fmt.Fprintf(os.Stderr, "testing: %s\n", err) 76 os.Exit(2) 77 } 78 } 79 80 // coverReport reports the coverage percentage and writes a coverage profile if requested. 81 func coverReport() { 82 if goexperiment.CoverageRedesign { 83 coverReport2() 84 return 85 } 86 var f *os.File 87 var err error 88 if *coverProfile != "" { 89 f, err = os.Create(toOutputDir(*coverProfile)) 90 mustBeNil(err) 91 fmt.Fprintf(f, "mode: %s\n", cover.Mode) 92 defer func() { mustBeNil(f.Close()) }() 93 } 94 95 var active, total int64 96 var count uint32 97 for name, counts := range cover.Counters { 98 blocks := cover.Blocks[name] 99 for i := range counts { 100 stmts := int64(blocks[i].Stmts) 101 total += stmts 102 count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. 103 if count > 0 { 104 active += stmts 105 } 106 if f != nil { 107 _, err := fmt.Fprintf(f, "%s:%d.%d,%d.%d %d %d\n", name, 108 blocks[i].Line0, blocks[i].Col0, 109 blocks[i].Line1, blocks[i].Col1, 110 stmts, 111 count) 112 mustBeNil(err) 113 } 114 } 115 } 116 if total == 0 { 117 fmt.Println("coverage: [no statements]") 118 return 119 } 120 fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages) 121 }