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

ghettovoice / abnf / 18802781153

25 Oct 2025 12:03PM UTC coverage: 70.875% (-0.04%) from 70.919%
18802781153

push

github

ghettovoice
Fix missed error wrapping

1 of 1 new or added line in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

1611 of 2273 relevant lines covered (70.88%)

54.52 hits per line

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

73.27
/errors.go
1
package abnf
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7
        "strings"
8
        "sync"
9
        "sync/atomic"
10
)
11

12
// ErrNotMatched is returned by operators when input doesn't match.
13
const ErrNotMatched sentinelError = "not matched"
14

15
var detailErrs atomic.Bool
16

17
// EnableDetailedErrors enables detailed operator errors.
18
// Detailed errors provide more information about the error
19
// including the operator key and position.
20
// By default, detailed errors are disabled.
21
func EnableDetailedErrors() { detailErrs.Store(true) }
1✔
22

23
// DisableDetailedErrors disables detailed operator errors.
24
// By default, detailed errors are disabled.
25
func DisableDetailedErrors() { detailErrs.Store(false) }
1✔
26

27
type sentinelError string
28

29
func (e sentinelError) Error() string { return string(e) }
2✔
30

31
type operError struct {
32
        op  string
33
        pos uint
34
        err error
35
}
36

UNCOV
37
func (e operError) Unwrap() error { return e.err }
×
38

39
func (e operError) Error() string {
1✔
40
        sb := bytes.NewBuffer(make([]byte, 0, 128))
1✔
41
        e.writeError(sb, 0)
1✔
42
        return sb.String()
1✔
43
}
1✔
44

45
func (e operError) writeError(sb *bytes.Buffer, depth int) {
4✔
46
        fmt.Fprintf(sb, "operator %q failed at position %d:", e.op, e.pos)
4✔
47

4✔
48
        var merr *multiError
4✔
49
        if errors.As(e.err, &merr) {
6✔
50
                merr.writeError(sb, depth)
2✔
51
        } else {
4✔
52
                sb.WriteString(" ")
2✔
53
                sb.WriteString(e.err.Error())
2✔
54
        }
2✔
55
}
56

57
type multiError []error
58

59
func (e *multiError) Unwrap() []error {
11✔
60
        if e == nil {
11✔
61
                return nil
×
62
        }
×
63
        return *e
11✔
64
}
65

66
func (e *multiError) Error() string {
×
67
        if e == nil {
×
68
                return "<nil>"
×
69
        }
×
70

71
        sb := bytes.NewBuffer(make([]byte, 0, 128))
×
72
        e.writeError(sb, 0)
×
73
        return sb.String()
×
74
}
75

76
func (e *multiError) writeError(sb *bytes.Buffer, depth int) {
2✔
77
        sb.WriteString("\n")
2✔
78

2✔
79
        for i, err := range *e {
5✔
80
                if i > 0 {
4✔
81
                        sb.WriteString("\n")
1✔
82
                }
1✔
83

84
                var (
3✔
85
                        me *multiError
3✔
86
                        oe operError
3✔
87
                )
3✔
88
                if errors.As(err, &oe) {
6✔
89
                        sb.WriteString(strings.Repeat("  ", depth+1))
3✔
90
                        sb.WriteString("- ")
3✔
91
                        oe.writeError(sb, depth+1)
3✔
92
                } else if errors.As(err, &me) {
3✔
93
                        me.writeError(sb, depth+1)
×
94
                } else {
×
95
                        sb.WriteString(strings.Repeat("  ", depth+1))
×
96
                        sb.WriteString("- ")
×
97
                        sb.WriteString(err.Error())
×
98
                }
×
99
        }
100
}
101

102
const multiErrCap = 3
103

104
var multiErrPool = &sync.Pool{
105
        New: func() any {
10✔
106
                me := make(multiError, 0, multiErrCap)
10✔
107
                return &me
10✔
108
        },
10✔
109
}
110

111
func newMultiErr(c uint) *multiError {
29✔
112
        var err *multiError
29✔
113
        if c <= multiErrCap {
58✔
114
                err = multiErrPool.Get().(*multiError)
29✔
115
        } else {
29✔
116
                me := make(multiError, 0, c)
×
117
                err = &me
×
118
        }
×
119
        return err
29✔
120
}
121

122
func (e *multiError) clear() {
111✔
123
        if e == nil {
170✔
124
                return
59✔
125
        }
59✔
126

127
        clear(*e)
52✔
128
        *e = (*e)[:0]
52✔
129
}
130

131
func (e *multiError) free() {
41✔
132
        if e == nil || cap(*e) > 10*multiErrCap {
56✔
133
                return
15✔
134
        }
15✔
135

136
        e.clear()
26✔
137
        multiErrPool.Put(e)
26✔
138
}
139

140
func wrapOperError(op string, pos uint, err error) error {
68✔
141
        if err == nil {
68✔
142
                return nil
×
143
        }
×
144

145
        if !detailErrs.Load() {
130✔
146
                if errors.Is(err, ErrNotMatched) {
124✔
147
                        if me, ok := err.(*multiError); ok {
70✔
148
                                me.free()
8✔
149
                        }
8✔
150
                        if oe, ok := err.(operError); ok {
62✔
151
                                if me, ok := oe.err.(*multiError); ok {
×
152
                                        me.free()
×
153
                                }
×
154
                        }
155
                        return ErrNotMatched
62✔
156
                }
157
                return err
×
158
        }
159

160
        var oerr operError
6✔
161
        if errors.As(err, &oerr) && oerr.op == op && oerr.pos == pos {
6✔
162
                return err
×
163
        }
×
164

165
        return operError{op: op, pos: pos, err: err}
6✔
166
}
167

168
func wrapNotMatched(op string, pos uint) error {
54✔
169
        return wrapOperError(op, pos, ErrNotMatched)
54✔
170
}
54✔
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