Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 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" |
Rob Pike | d33ee0c | 2014-09-09 12:31:07 -0700 | [diff] [blame] | 12 | "sync/atomic" |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 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 | |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 26 | var cover Cover |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 27 | |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 28 | // Cover records information about test coverage checking. |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 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. |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 31 | type Cover struct { |
| 32 | Mode string |
| 33 | Counters map[string][]uint32 |
| 34 | Blocks map[string][]CoverBlock |
| 35 | CoveredPackages string |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 36 | } |
| 37 | |
Russ Cox | d2d7187 | 2014-07-22 22:56:35 -0400 | [diff] [blame] | 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 { |
Rob Pike | d33ee0c | 2014-09-09 12:31:07 -0700 | [diff] [blame] | 48 | for i := range counters { |
| 49 | if atomic.LoadUint32(&counters[i]) > 0 { |
Russ Cox | d2d7187 | 2014-07-22 22:56:35 -0400 | [diff] [blame] | 50 | n++ |
| 51 | } |
| 52 | d++ |
| 53 | } |
| 54 | } |
| 55 | if d == 0 { |
| 56 | return 0 |
| 57 | } |
| 58 | return float64(n) / float64(d) |
| 59 | } |
| 60 | |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 61 | // RegisterCover records the coverage data accumulators for the tests. |
Rob Pike | 6d86c14 | 2013-07-10 09:52:36 +1000 | [diff] [blame] | 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. |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 64 | func RegisterCover(c Cover) { |
| 65 | cover = c |
Rob Pike | 6d86c14 | 2013-07-10 09:52:36 +1000 | [diff] [blame] | 66 | } |
| 67 | |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 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) |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 83 | fmt.Fprintf(f, "mode: %s\n", cover.Mode) |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 84 | defer func() { mustBeNil(f.Close()) }() |
| 85 | } |
| 86 | |
| 87 | var active, total int64 |
Rob Pike | d33ee0c | 2014-09-09 12:31:07 -0700 | [diff] [blame] | 88 | var count uint32 |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 89 | for name, counts := range cover.Counters { |
| 90 | blocks := cover.Blocks[name] |
Rob Pike | d33ee0c | 2014-09-09 12:31:07 -0700 | [diff] [blame] | 91 | for i := range counts { |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 92 | stmts := int64(blocks[i].Stmts) |
| 93 | total += stmts |
Rob Pike | d33ee0c | 2014-09-09 12:31:07 -0700 | [diff] [blame] | 94 | count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 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 | } |
Russ Cox | ccc4553 | 2013-07-12 20:40:30 -0400 | [diff] [blame] | 111 | fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages) |
Rob Pike | 8e8b8b8 | 2013-06-18 14:18:25 -0700 | [diff] [blame] | 112 | } |