Source file src/testing/cover.go

     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  }
   125  

View as plain text