github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/service/perl/file.go (about)

     1  package perl
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/covergates/covergates/core"
     7  	log "github.com/sirupsen/logrus"
     8  )
     9  
    10  // FileCollection of Perl source codes
    11  type FileCollection struct {
    12  	collect map[string][]*core.File
    13  }
    14  
    15  type statementSlice []*core.StatementHit
    16  
    17  func (s statementSlice) Len() int           { return len(s) }
    18  func (s statementSlice) Less(i, j int) bool { return s[i].LineNumber < s[j].LineNumber }
    19  func (s statementSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    20  
    21  func newStatementHits(digest *coverDigest) []*core.StatementHit {
    22  	statements := make([]*core.StatementHit, len(digest.Statement))
    23  	for i, line := range digest.Statement {
    24  		statements[i] = &core.StatementHit{
    25  			LineNumber: line,
    26  		}
    27  	}
    28  	return statements
    29  }
    30  
    31  func newFile(name string, count *coverCount, digest *coverDigest) *core.File {
    32  	statements := newStatementHits(digest)
    33  	if len(count.Statement) > len(statements) {
    34  		log.Warningf("%s statement count does match to digest, will ignore extra statements", name)
    35  		log.Debug(count)
    36  		log.Debug(digest)
    37  	}
    38  	for i, c := range count.Statement {
    39  		if i >= len(statements) {
    40  			continue
    41  		}
    42  		statements[i].Hits = c
    43  	}
    44  	return &core.File{
    45  		Name:          name,
    46  		StatementHits: statements,
    47  	}
    48  }
    49  
    50  func newFileCollection() *FileCollection {
    51  	return &FileCollection{
    52  		collect: make(map[string][]*core.File),
    53  	}
    54  }
    55  
    56  func (c *FileCollection) add(file *core.File) {
    57  	files, ok := c.collect[file.Name]
    58  	if !ok {
    59  		files = make([]*core.File, 0)
    60  	}
    61  	c.collect[file.Name] = append(files, file)
    62  }
    63  
    64  func sumStatementCoverage(hits []*core.StatementHit) float64 {
    65  	if len(hits) <= 0 {
    66  		return 0.0
    67  	}
    68  	s := 0
    69  	for _, hit := range hits {
    70  		if hit.Hits > 0 {
    71  			s++
    72  		}
    73  	}
    74  	return float64(s) / float64(len(hits))
    75  }
    76  
    77  func mergeFiles(files []*core.File) *core.File {
    78  	if len(files) <= 0 {
    79  		return nil
    80  	}
    81  	seed := files[0]
    82  	hits := make([]*core.StatementHit, len(seed.StatementHits))
    83  	for i, hit := range seed.StatementHits {
    84  		hits[i] = hit.Copy()
    85  	}
    86  	merged := &core.File{
    87  		Name:          seed.Name,
    88  		StatementHits: hits,
    89  	}
    90  	for _, file := range files[1:] {
    91  		for i, hit := range file.StatementHits {
    92  			merged.StatementHits[i].Hits += hit.Hits
    93  		}
    94  	}
    95  	merged.StatementCoverage = sumStatementCoverage(merged.StatementHits)
    96  	return merged
    97  }
    98  
    99  func (c *FileCollection) mergedFiles() []*core.File {
   100  	files := make([]*core.File, 0)
   101  	for _, collect := range c.collect {
   102  		merged := mergeFiles(collect)
   103  		mergeStatementHist(merged)
   104  		files = append(files, merged)
   105  	}
   106  	return files
   107  }
   108  
   109  func mergeStatementHist(file *core.File) {
   110  	hitMap := make(map[int]*core.StatementHit)
   111  	for _, hit := range file.StatementHits {
   112  		if h, ok := hitMap[hit.LineNumber]; ok {
   113  			hit.Hits += h.Hits
   114  		}
   115  		hitMap[hit.LineNumber] = hit
   116  	}
   117  	statements := make(statementSlice, 0)
   118  	for _, hit := range hitMap {
   119  		statements = append(statements, hit)
   120  	}
   121  	sort.Sort(statements)
   122  	file.StatementHits = statements
   123  }