package cfile
import (
"encoding/json"
"fmt"
"internal/coverage"
"internal/coverage/calloc"
"internal/coverage/cformat"
"internal/coverage/cmerge"
"internal/coverage/decodecounter"
"internal/coverage/decodemeta"
"internal/coverage/pods"
"internal/coverage/rtcov"
"internal/runtime/atomic"
"io"
"os"
"path/filepath"
"strings"
"unsafe"
)
func ProcessCoverTestDir (dir string , cfile string , cm string , cpkg string , w io .Writer , selpkgs []string ) error {
cmode := coverage .ParseCounterMode (cm )
if cmode == coverage .CtrModeInvalid {
return fmt .Errorf ("invalid counter mode %q" , cm )
}
ml := rtcov .Meta .List
if len (ml ) == 0 {
} else {
if err := emitMetaDataToDirectory (dir , ml ); err != nil {
return err
}
if err := emitCounterDataToDirectory (dir ); err != nil {
return err
}
}
podlist , err := pods .CollectPods ([]string {dir }, false )
if err != nil {
return fmt .Errorf ("reading from %s: %v" , dir , err )
}
var tf *os .File
var tfClosed bool
if cfile != "" {
var err error
tf , err = os .Create (cfile )
if err != nil {
return fmt .Errorf ("internal error: opening coverage data output file %q: %v" , cfile , err )
}
defer func () {
if !tfClosed {
tfClosed = true
tf .Close ()
}
}()
}
ts := &tstate {
cm : &cmerge .Merger {},
cf : cformat .NewFormatter (cmode ),
cmode : cmode ,
}
hashstring := fmt .Sprintf ("%x" , finalHash )
importpaths := make (map [string ]struct {})
for _ , p := range podlist {
if !strings .Contains (p .MetaFile , hashstring ) {
continue
}
if err := ts .processPod (p , importpaths ); err != nil {
return err
}
}
metafilespath := filepath .Join (dir , coverage .MetaFilesFileName )
if _ , err := os .Stat (metafilespath ); err == nil {
if err := ts .readAuxMetaFiles (metafilespath , importpaths ); err != nil {
return err
}
}
if err := ts .cf .EmitPercent (w , selpkgs , cpkg , true , true ); err != nil {
return err
}
if tf != nil {
if err := ts .cf .EmitTextual (tf ); err != nil {
return err
}
tfClosed = true
if err := tf .Close (); err != nil {
return fmt .Errorf ("closing %s: %v" , cfile , err )
}
}
return nil
}
type tstate struct {
calloc .BatchCounterAlloc
cm *cmerge .Merger
cf *cformat .Formatter
cmode coverage .CounterMode
}
func (ts *tstate ) processPod (p pods .Pod , importpaths map [string ]struct {}) error {
f , err := os .Open (p .MetaFile )
if err != nil {
return fmt .Errorf ("unable to open meta-data file %s: %v" , p .MetaFile , err )
}
defer func () {
f .Close ()
}()
var mfr *decodemeta .CoverageMetaFileReader
mfr , err = decodemeta .NewCoverageMetaFileReader (f , nil )
if err != nil {
return fmt .Errorf ("error reading meta-data file %s: %v" , p .MetaFile , err )
}
newmode := mfr .CounterMode ()
if newmode != ts .cmode {
return fmt .Errorf ("internal error: counter mode clash: %q from test harness, %q from data file %s" , ts .cmode .String (), newmode .String (), p .MetaFile )
}
newgran := mfr .CounterGranularity ()
if err := ts .cm .SetModeAndGranularity (p .MetaFile , cmode , newgran ); err != nil {
return err
}
pmm := make (map [pkfunc ][]uint32 )
readcdf := func (cdf string ) error {
cf , err := os .Open (cdf )
if err != nil {
return fmt .Errorf ("opening counter data file %s: %s" , cdf , err )
}
defer cf .Close ()
var cdr *decodecounter .CounterDataReader
cdr , err = decodecounter .NewCounterDataReader (cdf , cf )
if err != nil {
return fmt .Errorf ("reading counter data file %s: %s" , cdf , err )
}
var data decodecounter .FuncPayload
for {
ok , err := cdr .NextFunc (&data )
if err != nil {
return fmt .Errorf ("reading counter data file %s: %v" , cdf , err )
}
if !ok {
break
}
key := pkfunc {pk : data .PkgIdx , fcn : data .FuncIdx }
if prev , found := pmm [key ]; found {
if err , _ := ts .cm .MergeCounters (data .Counters , prev ); err != nil {
return fmt .Errorf ("processing counter data file %s: %v" , cdf , err )
}
}
c := ts .AllocateCounters (len (data .Counters ))
copy (c , data .Counters )
pmm [key ] = c
}
return nil
}
for _ , cdf := range p .CounterDataFiles {
if err := readcdf (cdf ); err != nil {
return err
}
}
np := uint32 (mfr .NumPackages ())
payload := []byte {}
for pkIdx := uint32 (0 ); pkIdx < np ; pkIdx ++ {
var pd *decodemeta .CoverageMetaDataDecoder
pd , payload , err = mfr .GetPackageDecoder (pkIdx , payload )
if err != nil {
return fmt .Errorf ("reading pkg %d from meta-file %s: %s" , pkIdx , p .MetaFile , err )
}
ts .cf .SetPackage (pd .PackagePath ())
importpaths [pd .PackagePath ()] = struct {}{}
var fd coverage .FuncDesc
nf := pd .NumFuncs ()
for fnIdx := uint32 (0 ); fnIdx < nf ; fnIdx ++ {
if err := pd .ReadFunc (fnIdx , &fd ); err != nil {
return fmt .Errorf ("reading meta-data file %s: %v" ,
p .MetaFile , err )
}
key := pkfunc {pk : pkIdx , fcn : fnIdx }
counters , haveCounters := pmm [key ]
for i := 0 ; i < len (fd .Units ); i ++ {
u := fd .Units [i ]
if u .Parent != 0 {
continue
}
count := uint32 (0 )
if haveCounters {
count = counters [i ]
}
ts .cf .AddUnit (fd .Srcfile , fd .Funcname , fd .Lit , u , count )
}
}
}
return nil
}
type pkfunc struct {
pk, fcn uint32
}
func (ts *tstate ) readAuxMetaFiles (metafiles string , importpaths map [string ]struct {}) error {
var mfc coverage .MetaFileCollection
data , err := os .ReadFile (metafiles )
if err != nil {
return fmt .Errorf ("error reading auxmetafiles file %q: %v" , metafiles , err )
}
if err := json .Unmarshal (data , &mfc ); err != nil {
return fmt .Errorf ("error reading auxmetafiles file %q: %v" , metafiles , err )
}
for i := range mfc .ImportPaths {
p := mfc .ImportPaths [i ]
if _ , ok := importpaths [p ]; ok {
continue
}
var pod pods .Pod
pod .MetaFile = mfc .MetaFileFragments [i ]
if err := ts .processPod (pod , importpaths ); err != nil {
return err
}
}
return nil
}
func Snapshot () float64 {
cl := getCovCounterList ()
if len (cl ) == 0 {
return 0.0
}
tot := uint64 (0 )
totExec := uint64 (0 )
for _ , c := range cl {
sd := unsafe .Slice ((*atomic .Uint32 )(unsafe .Pointer (c .Counters )), c .Len )
tot += uint64 (len (sd ))
for i := 0 ; i < len (sd ); i ++ {
if sd [i ].Load () == 0 {
continue
}
nCtrs := sd [i +coverage .NumCtrsOffset ].Load ()
cst := i + coverage .FirstCtrOffset
if cst +int (nCtrs ) > len (sd ) {
break
}
counters := sd [cst : cst +int (nCtrs )]
for i := range counters {
if counters [i ].Load () != 0 {
totExec ++
}
}
i += coverage .FirstCtrOffset + int (nCtrs ) - 1
}
}
if tot == 0 {
return 0.0
}
return float64 (totExec ) / float64 (tot )
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .