// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package coverage

import (
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
)

// processCoverTestDir is called (via a linknamed reference) from
// testmain code when "go test -cover" is in effect. It is not
// intended to be used other than internally by the Go command's
// generated code.
func processCoverTestDir( string,  string,  string,  string) error {
	return processCoverTestDirInternal(, , , , os.Stdout)
}

// processCoverTestDirInternal is an io.Writer version of processCoverTestDir,
// exposed for unit testing.
func processCoverTestDirInternal( string,  string,  string,  string,  io.Writer) error {
	 := coverage.ParseCounterMode()
	if  == coverage.CtrModeInvalid {
		return fmt.Errorf("invalid counter mode %q", )
	}

	// Emit meta-data and counter data.
	 := getCovMetaList()
	if len() == 0 {
		// This corresponds to the case where we have a package that
		// contains test code but no functions (which is fine). In this
		// case there is no need to emit anything.
	} else {
		if  := emitMetaDataToDirectory(, );  != nil {
			return 
		}
		if  := emitCounterDataToDirectory();  != nil {
			return 
		}
	}

	// Collect pods from test run. For the majority of cases we would
	// expect to see a single pod here, but allow for multiple pods in
	// case the test harness is doing extra work to collect data files
	// from builds that it kicks off as part of the testing.
	,  := pods.CollectPods([]string{}, false)
	if  != nil {
		return fmt.Errorf("reading from %s: %v", , )
	}

	// Open text output file if appropriate.
	var  *os.File
	var  bool
	if  != "" {
		var  error
		,  = os.Create()
		if  != nil {
			return fmt.Errorf("internal error: opening coverage data output file %q: %v", , )
		}
		defer func() {
			if ! {
				 = true
				.Close()
			}
		}()
	}

	// Read/process the pods.
	 := &tstate{
		cm:    &cmerge.Merger{},
		cf:    cformat.NewFormatter(),
		cmode: ,
	}
	// Generate the expected hash string based on the final meta-data
	// hash for this test, then look only for pods that refer to that
	// hash (just in case there are multiple instrumented executables
	// in play). See issue #57924 for more on this.
	 := fmt.Sprintf("%x", finalHash)
	 := make(map[string]struct{})
	for ,  := range  {
		if !strings.Contains(.MetaFile, ) {
			continue
		}
		if  := .processPod(, );  != nil {
			return 
		}
	}

	 := filepath.Join(, coverage.MetaFilesFileName)
	if ,  := os.Stat();  == nil {
		if  := .readAuxMetaFiles(, );  != nil {
			return 
		}
	}

	// Emit percent.
	if  := .cf.EmitPercent(, , true, true);  != nil {
		return 
	}

	// Emit text output.
	if  != nil {
		if  := .cf.EmitTextual();  != nil {
			return 
		}
		 = true
		if  := .Close();  != nil {
			return fmt.Errorf("closing %s: %v", , )
		}
	}

	return nil
}

type tstate struct {
	calloc.BatchCounterAlloc
	cm    *cmerge.Merger
	cf    *cformat.Formatter
	cmode coverage.CounterMode
}

// processPod reads coverage counter data for a specific pod.
func ( *tstate) ( pods.Pod,  map[string]struct{}) error {
	// Open meta-data file
	,  := os.Open(.MetaFile)
	if  != nil {
		return fmt.Errorf("unable to open meta-data file %s: %v", .MetaFile, )
	}
	defer func() {
		.Close()
	}()
	var  *decodemeta.CoverageMetaFileReader
	,  = decodemeta.NewCoverageMetaFileReader(, nil)
	if  != nil {
		return fmt.Errorf("error reading meta-data file %s: %v", .MetaFile, )
	}
	 := .CounterMode()
	if  != .cmode {
		return fmt.Errorf("internal error: counter mode clash: %q from test harness, %q from data file %s", .cmode.String(), .String(), .MetaFile)
	}
	 := .CounterGranularity()
	if  := .cm.SetModeAndGranularity(.MetaFile, cmode, );  != nil {
		return 
	}

	// A map to store counter data, indexed by pkgid/fnid tuple.
	 := make(map[pkfunc][]uint32)

	// Helper to read a single counter data file.
	 := func( string) error {
		,  := os.Open()
		if  != nil {
			return fmt.Errorf("opening counter data file %s: %s", , )
		}
		defer .Close()
		var  *decodecounter.CounterDataReader
		,  = decodecounter.NewCounterDataReader(, )
		if  != nil {
			return fmt.Errorf("reading counter data file %s: %s", , )
		}
		var  decodecounter.FuncPayload
		for {
			,  := .NextFunc(&)
			if  != nil {
				return fmt.Errorf("reading counter data file %s: %v", , )
			}
			if ! {
				break
			}

			// NB: sanity check on pkg and func IDs?
			 := pkfunc{pk: .PkgIdx, fcn: .FuncIdx}
			if ,  := [];  {
				// Note: no overflow reporting here.
				if ,  := .cm.MergeCounters(.Counters, );  != nil {
					return fmt.Errorf("processing counter data file %s: %v", , )
				}
			}
			 := .AllocateCounters(len(.Counters))
			copy(, .Counters)
			[] = 
		}
		return nil
	}

	// Read counter data files.
	for ,  := range .CounterDataFiles {
		if  := ();  != nil {
			return 
		}
	}

	// Visit meta-data file.
	 := uint32(.NumPackages())
	 := []byte{}
	for  := uint32(0);  < ; ++ {
		var  *decodemeta.CoverageMetaDataDecoder
		, ,  = .GetPackageDecoder(, )
		if  != nil {
			return fmt.Errorf("reading pkg %d from meta-file %s: %s", , .MetaFile, )
		}
		.cf.SetPackage(.PackagePath())
		[.PackagePath()] = struct{}{}
		var  coverage.FuncDesc
		 := .NumFuncs()
		for  := uint32(0);  < ; ++ {
			if  := .ReadFunc(, &);  != nil {
				return fmt.Errorf("reading meta-data file %s: %v",
					.MetaFile, )
			}
			 := pkfunc{pk: , fcn: }
			,  := []
			for  := 0;  < len(.Units); ++ {
				 := .Units[]
				// Skip units with non-zero parent (no way to represent
				// these in the existing format).
				if .Parent != 0 {
					continue
				}
				 := uint32(0)
				if  {
					 = []
				}
				.cf.AddUnit(.Srcfile, .Funcname, .Lit, , )
			}
		}
	}
	return nil
}

type pkfunc struct {
	pk, fcn uint32
}

func ( *tstate) ( string,  map[string]struct{}) error {
	// Unmarshall the information on available aux metafiles into
	// a MetaFileCollection struct.
	var  coverage.MetaFileCollection
	,  := os.ReadFile()
	if  != nil {
		return fmt.Errorf("error reading auxmetafiles file %q: %v", , )
	}
	if  := json.Unmarshal(, &);  != nil {
		return fmt.Errorf("error reading auxmetafiles file %q: %v", , )
	}

	// Walk through each available aux meta-file. If we've already
	// seen the package path in question during the walk of the
	// "regular" meta-data file, then we can skip the package,
	// otherwise construct a dummy pod with the single meta-data file
	// (no counters) and invoke processPod on it.
	for  := range .ImportPaths {
		 := .ImportPaths[]
		if ,  := [];  {
			continue
		}
		var  pods.Pod
		.MetaFile = .MetaFileFragments[]
		if  := .processPod(, );  != nil {
			return 
		}
	}
	return nil
}

// snapshot returns a snapshot of coverage percentage at a moment of
// time within a running test, so as to support the testing.Coverage()
// function. This version doesn't examine coverage meta-data, so the
// result it returns will be less accurate (more "slop") due to the
// fact that we don't look at the meta data to see how many statements
// are associated with each counter.
func snapshot() float64 {
	 := getCovCounterList()
	if len() == 0 {
		// no work to do here.
		return 0.0
	}

	 := uint64(0)
	 := uint64(0)
	for ,  := range  {
		 := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(.Counters)), .Len)
		 += uint64(len())
		for  := 0;  < len(); ++ {
			// Skip ahead until the next non-zero value.
			if [].Load() == 0 {
				continue
			}
			// We found a function that was executed.
			 := [+coverage.NumCtrsOffset].Load()
			 :=  + coverage.FirstCtrOffset

			if +int() > len() {
				break
			}
			 := [ : +int()]
			for  := range  {
				if [].Load() != 0 {
					++
				}
			}
			 += coverage.FirstCtrOffset + int() - 1
		}
	}
	if  == 0 {
		return 0.0
	}
	return float64() / float64()
}