Skip to content

Commit 10e3c1b

Browse files
feat: Add IdentifierStartsWith
Signed-off-by: Anthony TREUILLIER <anthony.treuillier@scality.com>
1 parent 2f1f877 commit 10e3c1b

3 files changed

Lines changed: 82 additions & 2 deletions

File tree

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,17 @@ e2.Is(e1) return True // e1 is a parent of e2
182182
e1.Is(e2) return False
183183
```
184184

185+
### Specific use-case with IdentifierStartsWith()
186+
187+
`IdentifierStartsWith(error, prefix)` checks whether this error's identifier, formatted as a string, starts with the given prefix.
188+
189+
For example:
190+
If e.Identifier: "3-2-1", then
191+
```go
192+
IdentifierStartsWith(e, "3-2") return True
193+
IdentifierStartsWith(e, "2-1") return False
194+
```
195+
185196
## Output Format
186197

187198
The `Error()` method produces output in the following format:

errors.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"strings"
1515
)
1616

17+
const separator = "-"
18+
1719
// Trace represents a single entry in an error's stack trace.
1820
// It captures the location and time when an error was thrown or stamped.
1921
type Trace struct {
@@ -178,6 +180,26 @@ func Is(err, target error) bool { return errors.Is(err, target) }
178180
// As is a wrapper around errors.As to check if the error is of a specific type.
179181
func As(err error, target any) bool { return errors.As(err, target) }
180182

183+
// IdentifierStartsWith checks if the error's identifier starts with the given prefix.
184+
func IdentifierStartsWith(err error, prefix string) bool {
185+
var e *Error
186+
if !errors.As(err, &e) {
187+
return false
188+
}
189+
190+
if prefix == "" {
191+
return true
192+
}
193+
194+
// To avoid uint32 conversion and errors handling, we decided to compare:
195+
// * the identifier, suffixed with an hyphen
196+
// * the prefix, suffixed with an hyphen
197+
return strings.HasPrefix(
198+
e.GetIdentifier()+separator,
199+
prefix+separator,
200+
)
201+
}
202+
181203
// Unwrap returns the underlying cause of this error, nil if no cause.
182204
func Unwrap(err error) error {
183205
u, ok := err.(interface {
@@ -329,7 +351,7 @@ func trace() *Trace {
329351
}
330352
}
331353

332-
// GetIdentifier returns a string with all identifiers reversed and joined by a hyphen ("-").
354+
// GetIdentifier returns a string with all identifiers reversed and joined by a hyphen (-).
333355
func (e *Error) GetIdentifier() string {
334356
if len(e.Identifier) == 0 {
335357
return ""
@@ -354,7 +376,7 @@ func (e *Error) GetIdentifier() string {
354376

355377
// Append the separator for all elements except the last one.
356378
if i < len(clone)-1 {
357-
builder.WriteString("-")
379+
builder.WriteString(separator)
358380
}
359381
}
360382

errors_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,53 @@ var _ = Describe("Errors", func() {
445445
})
446446
})
447447

448+
Context("When comparing error with IdentifierStartsWith", func() {
449+
It("should return true when error's identifier starts with the prefix", func() {
450+
e := Wrap(ErrForbidden, WithIdentifier(1))
451+
Expect(IdentifierStartsWith(e, "1")).To(BeTrue())
452+
})
453+
454+
It("should return true when error's identifiers start with the prefix", func() {
455+
e1_1 := Wrap(ErrForbidden, WithIdentifier(12))
456+
e1_2 := Wrap(e1_1, WithIdentifier(22))
457+
e1_3 := Wrap(e1_2, WithIdentifier(31))
458+
Expect(IdentifierStartsWith(e1_3, "3")).To(BeFalse())
459+
Expect(IdentifierStartsWith(e1_3, "31")).To(BeTrue())
460+
Expect(IdentifierStartsWith(e1_3, "31-2")).To(BeFalse())
461+
Expect(IdentifierStartsWith(e1_3, "31-22")).To(BeTrue())
462+
Expect(IdentifierStartsWith(e1_3, "31-22-1")).To(BeFalse())
463+
Expect(IdentifierStartsWith(e1_3, "31-22-12")).To(BeTrue())
464+
})
465+
466+
It("should return false when error's identifier does not start with the prefix", func() {
467+
e := Wrap(ErrForbidden, WithIdentifier(1))
468+
Expect(IdentifierStartsWith(e, "2")).To(BeFalse())
469+
})
470+
471+
It("should return false when error's identifiers do not start with the prefix", func() {
472+
e1_1 := Wrap(ErrForbidden, WithIdentifier(1))
473+
e1_2 := Wrap(e1_1, WithIdentifier(2))
474+
e1_3 := Wrap(e1_2, WithIdentifier(3))
475+
Expect(IdentifierStartsWith(e1_3, "1")).To(BeFalse())
476+
Expect(IdentifierStartsWith(e1_3, "2")).To(BeFalse())
477+
Expect(IdentifierStartsWith(e1_3, "2-1")).To(BeFalse())
478+
})
479+
480+
It("should return false when error is not an *Error", func() {
481+
e := errTest
482+
Expect(IdentifierStartsWith(e, "1")).To(BeFalse())
483+
})
484+
485+
It("should return false when error is nil", func() {
486+
Expect(IdentifierStartsWith(nil, "1")).To(BeFalse())
487+
})
488+
489+
It("should return true when empty prefix", func() {
490+
e := Wrap(ErrForbidden, WithIdentifier(1))
491+
Expect(IdentifierStartsWith(e, "")).To(BeTrue())
492+
})
493+
})
494+
448495
Context("When unwrapping errors", func() {
449496
It("should return the cause when present", func() {
450497
e := Wrap(ErrForbidden, CausedBy(errPerm))

0 commit comments

Comments
 (0)