...

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		"os"
    12		"sync/atomic"
    13	)
    14	
    15	// CoverBlock records the coverage data for a single basic block.
    16	// The fields are 1-indexed, as in an editor: The opening line of
    17	// the file is number 1, for example. Columns are measured
    18	// in bytes.
    19	// NOTE: This struct is internal to the testing infrastructure and may change.
    20	// It is not covered (yet) by the Go 1 compatibility guidelines.
    21	type CoverBlock struct {
    22		Line0 uint32 // Line number for block start.
    23		Col0  uint16 // Column number for block start.
    24		Line1 uint32 // Line number for block end.
    25		Col1  uint16 // Column number for block end.
    26		Stmts uint16 // Number of statements included in this block.
    27	}
    28	
    29	var cover Cover
    30	
    31	// Cover records information about test coverage checking.
    32	// NOTE: This struct is internal to the testing infrastructure and may change.
    33	// It is not covered (yet) by the Go 1 compatibility guidelines.
    34	type Cover struct {
    35		Mode            string
    36		Counters        map[string][]uint32
    37		Blocks          map[string][]CoverBlock
    38		CoveredPackages string
    39	}
    40	
    41	// Coverage reports the current code coverage as a fraction in the range [0, 1].
    42	// If coverage is not enabled, Coverage returns 0.
    43	//
    44	// When running a large set of sequential test cases, checking Coverage after each one
    45	// can be useful for identifying which test cases exercise new code paths.
    46	// It is not a replacement for the reports generated by 'go test -cover' and
    47	// 'go tool cover'.
    48	func Coverage() float64 {
    49		var n, d int64
    50		for _, counters := range cover.Counters {
    51			for i := range counters {
    52				if atomic.LoadUint32(&counters[i]) > 0 {
    53					n++
    54				}
    55				d++
    56			}
    57		}
    58		if d == 0 {
    59			return 0
    60		}
    61		return float64(n) / float64(d)
    62	}
    63	
    64	// RegisterCover records the coverage data accumulators for the tests.
    65	// NOTE: This function is internal to the testing infrastructure and may change.
    66	// It is not covered (yet) by the Go 1 compatibility guidelines.
    67	func RegisterCover(c Cover) {
    68		cover = c
    69	}
    70	
    71	// mustBeNil checks the error and, if present, reports it and exits.
    72	func mustBeNil(err error) {
    73		if err != nil {
    74			fmt.Fprintf(os.Stderr, "testing: %s\n", err)
    75			os.Exit(2)
    76		}
    77	}
    78	
    79	// coverReport reports the coverage percentage and writes a coverage profile if requested.
    80	func coverReport() {
    81		var f *os.File
    82		var err error
    83		if *coverProfile != "" {
    84			f, err = os.Create(toOutputDir(*coverProfile))
    85			mustBeNil(err)
    86			fmt.Fprintf(f, "mode: %s\n", cover.Mode)
    87			defer func() { mustBeNil(f.Close()) }()
    88		}
    89	
    90		var active, total int64
    91		var count uint32
    92		for name, counts := range cover.Counters {
    93			blocks := cover.Blocks[name]
    94			for i := range counts {
    95				stmts := int64(blocks[i].Stmts)
    96				total += stmts
    97				count = atomic.LoadUint32(&counts[i]) // For -mode=atomic.
    98				if count > 0 {
    99					active += stmts
   100				}
   101				if f != nil {
   102					_, err := fmt.Fprintf(f, "%s:%d.%d,%d.%d %d %d\n", name,
   103						blocks[i].Line0, blocks[i].Col0,
   104						blocks[i].Line1, blocks[i].Col1,
   105						stmts,
   106						count)
   107					mustBeNil(err)
   108				}
   109			}
   110		}
   111		if total == 0 {
   112			fmt.Println("coverage: [no statements]")
   113			return
   114		}
   115		fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages)
   116	}
   117	

View as plain text