• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

AlexsanderHamir / prof / 16576913683

28 Jul 2025 06:17PM UTC coverage: 17.625% (+1.7%) from 15.974%
16576913683

push

github

web-flow
Completed Testing Coverage

43 of 47 new or added lines in 3 files covered. (91.49%)

279 of 1583 relevant lines covered (17.62%)

13.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/parser/api.go
1
package parser
2

3
import (
4
        "bufio"
5
        "errors"
6
        "fmt"
7
        "regexp"
8
        "strings"
9

10
        "github.com/AlexsanderHamir/prof/internal/args"
11
        "github.com/AlexsanderHamir/prof/internal/config"
12
        "github.com/AlexsanderHamir/prof/internal/shared"
13
)
14

15
const (
16
        funcNameRegexp       = `\.([^.(]+)(?:\([^)]*\))?$`
17
        floatRegexp          = `\d+(?:\.\d+)?`
18
        header               = "flat  flat%   sum%        cum   cum%"
19
        minProfileLinelength = 6
20
)
21

22
// Line Indexes.
23
const (
24
        flatIndex           = 0
25
        flatPercentageIndex = 1
26
        sumPercentageIndex  = 2
27
        cumIndex            = 3
28
        cumPercentageIndex  = 4
29
        functionNameIndex   = 5
30
)
31

32
var (
33
        funcNameRegexpCompiled = regexp.MustCompile(funcNameRegexp)
34
        floatRegexpCompiled    = regexp.MustCompile(floatRegexp)
35
)
36

37
// ProfileFilter collects filters for extracting function names from a profile.
38
type ProfileFilter struct {
39
        // Include only lines starting with specified prefix
40
        FunctionPrefixes []string
41

42
        // Ignore all functions after the last dot even if includes the above prefix
43
        IgnoreFunctions []string
44
}
45

46
type LineObj struct {
47
        FnName         string
48
        Flat           float64
49
        FlatPercentage float64
50
        SumPercentage  float64
51
        Cum            float64
52
        CumPercentage  float64
53
}
54

55
func TurnLinesIntoObjects(profilePath string) ([]*LineObj, error) {
×
56
        var lines []string
×
57

×
58
        scanner, file, err := shared.GetScanner(profilePath)
×
59
        if err != nil {
×
60
                return nil, err
×
61
        }
×
62
        defer file.Close()
×
63

×
NEW
64
        removeHeader(scanner)
×
65
        GetAllProfileLines(scanner, &lines)
×
66

×
67
        lineObjs, err := createLineObjects(lines)
×
68
        if err != nil {
×
69
                return nil, fmt.Errorf("failed creating line objects : %w", err)
×
70
        }
×
71

72
        return lineObjs, err
×
73
}
74

75
// GetAllFunctionNames extracts all function names from a profile text file, applying the given filter.
76
func GetAllFunctionNames(filePath string, filter config.FunctionFilter) (names []string, err error) {
×
77
        scanner, file, err := shared.GetScanner(filePath)
×
78
        if err != nil {
×
79
                return nil, fmt.Errorf("GetAllFunctionNames Failed: %w", err)
×
80
        }
×
81

82
        defer func() {
×
83
                if closeErr := file.Close(); closeErr != nil {
×
84
                        if err == nil {
×
85
                                err = fmt.Errorf("file close failed: %w", closeErr)
×
86
                        }
×
87
                }
88
        }()
89

90
        ignoreSet := getFilterSets(filter.IgnoreFunctions)
×
91

×
92
        var foundHeader bool
×
93
        for scanner.Scan() {
×
94
                line := strings.TrimSpace(scanner.Text())
×
95
                if line == "" {
×
96
                        continue
×
97
                }
98

99
                if strings.Contains(line, header) {
×
100
                        foundHeader = true
×
101
                        continue
×
102
                }
103

104
                // Skip lines until we find the header, then process profile data
105
                if !foundHeader {
×
106
                        continue
×
107
                }
108

109
                if funcName := extractFunctionName(line, filter.IncludePrefixes, ignoreSet); funcName != "" {
×
110
                        names = append(names, funcName)
×
111
                }
×
112
        }
113

114
        if err = scanner.Err(); err != nil {
×
115
                return nil, fmt.Errorf("error reading profile file: %w", err)
×
116
        }
×
117

118
        if !foundHeader {
×
119
                return nil, errors.New("profile file header not found")
×
120
        }
×
121

122
        return names, nil
×
123
}
124

125
// ShouldKeepLine determines if a line from a profile should be kept based on profile values and ignore filters.
126
func ShouldKeepLine(line string, agrs *args.LineFilterArgs) bool {
×
127
        if line == "" {
×
128
                return false
×
129
        }
×
130

131
        lineParts := strings.Fields(line)
×
132
        if len(lineParts) < minProfileLinelength {
×
133
                return false
×
134
        }
×
135

136
        if !filterByNumber(agrs.ProfileFilters, lineParts) {
×
137
                return false
×
138
        }
×
139

140
        if !filterByIgnoreFunctions(agrs.IgnoreFunctionSet, lineParts) {
×
141
                return false
×
142
        }
×
143

144
        return filterByIgnorePrefixes(agrs.IgnorePrefixSet, lineParts)
×
145
}
146

147
func GetAllProfileLines(scanner *bufio.Scanner, lines *[]string) {
×
148
        for scanner.Scan() {
×
149
                *lines = append(*lines, scanner.Text())
×
150
        }
×
151
}
152

NEW
153
func removeHeader(scanner *bufio.Scanner) {
×
154
        for scanner.Scan() {
×
155
                line := scanner.Text()
×
156
                if strings.Contains(line, header) {
×
157
                        break
×
158
                }
159
        }
160
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc