Home | History | Annotate | Download | only in testing
      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