...

Source file src/edge-infra.dev/third_party/gopherage/pkg/cov/merge.go

Documentation: edge-infra.dev/third_party/gopherage/pkg/cov

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cov
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"golang.org/x/tools/cover"
    23  	"sort"
    24  )
    25  
    26  // MergeProfiles merges two coverage profiles.
    27  // The profiles are expected to be similar - that is, from multiple invocations of a
    28  // single binary, or multiple binaries using the same codebase.
    29  // In particular, any source files with the same path must have had identical content
    30  // when building the binaries.
    31  // MergeProfiles expects its arguments to be sorted: Profiles in alphabetical order,
    32  // and lines in files in the order those lines appear. These are standard constraints for
    33  // Go coverage profiles. The resulting profile will also obey these constraints.
    34  func MergeProfiles(a []*cover.Profile, b []*cover.Profile) ([]*cover.Profile, error) {
    35  	var result []*cover.Profile
    36  	files := make(map[string]*cover.Profile, len(a))
    37  	for _, profile := range a {
    38  		np := deepCopyProfile(*profile)
    39  		result = append(result, &np)
    40  		files[np.FileName] = &np
    41  	}
    42  
    43  	needsSort := false
    44  	// Now merge b into the result
    45  	for _, profile := range b {
    46  		dest, ok := files[profile.FileName]
    47  		if ok {
    48  			if err := ensureProfilesMatch(profile, dest); err != nil {
    49  				return nil, fmt.Errorf("error merging %s: %v", profile.FileName, err)
    50  			}
    51  			for i, block := range profile.Blocks {
    52  				db := &dest.Blocks[i]
    53  				db.Count += block.Count
    54  			}
    55  		} else {
    56  			// If we get some file we haven't seen before, we just append it.
    57  			// We need to sort this later to ensure the resulting profile is still correctly sorted.
    58  			np := deepCopyProfile(*profile)
    59  			files[np.FileName] = &np
    60  			result = append(result, &np)
    61  			needsSort = true
    62  		}
    63  	}
    64  	if needsSort {
    65  		sort.Slice(result, func(i, j int) bool { return result[i].FileName < result[j].FileName })
    66  	}
    67  	return result, nil
    68  }
    69  
    70  // MergeMultipleProfiles merges more than two profiles together.
    71  // MergeMultipleProfiles is equivalent to calling MergeProfiles on pairs of profiles
    72  // until only one profile remains.
    73  func MergeMultipleProfiles(profiles [][]*cover.Profile) ([]*cover.Profile, error) {
    74  	if len(profiles) < 1 {
    75  		return nil, errors.New("can't merge zero profiles")
    76  	}
    77  	result := profiles[0]
    78  	for _, profile := range profiles[1:] {
    79  		var err error
    80  		if result, err = MergeProfiles(result, profile); err != nil {
    81  			return nil, err
    82  		}
    83  	}
    84  	return result, nil
    85  }
    86  

View as plain text