github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/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 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. 71 func RegisterCover(c Cover) { 72 cover = c 73 } 74 75 // mustBeNil checks the error and, if present, reports it and exits. 76 func 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. 84 func 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 }