github.com/thediveo/gons@v0.9.9/reexec/testing/testmain.go (about)

     1  package testing
     2  
     3  import (
     4  	"os"
     5  	"sync/atomic"
     6  	gotesting "testing"
     7  	_ "unsafe" // needed in order to use "go:linkname".
     8  
     9  	"github.com/thediveo/gons/reexec/internal/testsupport"
    10  )
    11  
    12  // In order to get complete coverage of our M.Run() during our own tests, we
    13  // have to resort to dirty tricks by accessing the package private
    14  // testing.cover variable which contains the complete coverage profile data
    15  // gathered.
    16  
    17  //go:linkname cover testing.cover
    18  var cover gotesting.Cover
    19  
    20  // coverageProfileFromCover returns the profile data from testing.cover, but
    21  // in our own coverage profile format.
    22  func coverageProfileFromTestingCover() *coverageProfile {
    23  	cp := newCoverageProfile()
    24  	cp.Mode = cover.Mode
    25  	var count uint32
    26  	for sourcename, counts := range cover.Counters {
    27  		source := &coverageProfileSource{
    28  			Blocks: make([]coverageProfileBlock, len(counts)),
    29  		}
    30  		cp.Sources[sourcename] = source
    31  		blocks := cover.Blocks[sourcename]
    32  		for idx := range counts {
    33  			count = atomic.LoadUint32(&counts[idx])
    34  			source.Blocks[idx] = coverageProfileBlock{
    35  				StartLine: blocks[idx].Line0,
    36  				StartCol:  blocks[idx].Col0,
    37  				EndLine:   blocks[idx].Line1,
    38  				EndCol:    blocks[idx].Col1,
    39  				NumStmts:  blocks[idx].Stmts,
    40  				Counts:    count,
    41  			}
    42  		}
    43  	}
    44  	return cp
    45  }
    46  
    47  // TestMainWithCoverage is only for our own testing, in order to gather "more
    48  // complete" coverage profile data including our M.Run()/M.run() methods.
    49  //
    50  // We achieve this with an unfortunate hack: we update the already written
    51  // coverage data after the fact, that is, after mm.run() (or its public
    52  // mm.Run() facade) has called gotesting.M.Run() which in turns writes the
    53  // coverage profile data. This way, we can also get coverage of the code parts
    54  // of ours M.run() which run after gotesting.M.Run().
    55  func TestMainWithCoverage(m *gotesting.M) {
    56  	mm := &M{M: m, skipCleanup: true}
    57  	exitcode, reexeced := mm.run()
    58  	if coverProfile != "" {
    59  		// Take the final coverage profile data as our starting point, ignoring
    60  		// whatever mm.run() wrote to the final coverage file. We need to write a
    61  		// new version of it with the most recent coverage profile data.
    62  		cp := coverageProfileFromTestingCover()
    63  		var merges []string
    64  		if !reexeced {
    65  			merges = testsupport.CoverageProfiles
    66  		}
    67  		mergeWithCoverProfileAndReport(cp, merges, coverProfile)
    68  		for _, coverprof := range merges {
    69  			_ = os.Remove(toOutputDir(coverprof))
    70  		}
    71  	}
    72  	os.Exit(exitcode)
    73  }