mirror of
https://github.com/google/uuid.git
synced 2024-11-21 17:16:42 +02:00
feat: add error types for better validation (#166)
* feat: add error types * fix: broken backward compatibility
This commit is contained in:
parent
d55c313874
commit
0e97ed3b53
53
uuid.go
53
uuid.go
@ -47,18 +47,40 @@ var (
|
||||
poolMu sync.Mutex
|
||||
poolPos = randPoolSize // protected with poolMu
|
||||
pool [randPoolSize]byte // protected with poolMu
|
||||
|
||||
ErrInvalidUUIDFormat = errors.New("invalid UUID format")
|
||||
ErrInvalidBracketedFormat = errors.New("invalid bracketed UUID format")
|
||||
)
|
||||
|
||||
type URNPrefixError struct { prefix string }
|
||||
|
||||
func (e URNPrefixError) Error() string {
|
||||
return fmt.Sprintf("invalid urn prefix: %q", e.prefix)
|
||||
}
|
||||
|
||||
func (e URNPrefixError) Is(target error) bool {
|
||||
_, ok := target.(URNPrefixError)
|
||||
return ok
|
||||
}
|
||||
|
||||
var ErrInvalidURNPrefix = URNPrefixError{}
|
||||
|
||||
type invalidLengthError struct{ len int }
|
||||
|
||||
func (err invalidLengthError) Error() string {
|
||||
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||
}
|
||||
|
||||
func (e invalidLengthError) Is(target error) bool {
|
||||
_, ok := target.(invalidLengthError)
|
||||
return ok
|
||||
}
|
||||
|
||||
var ErrInvalidLength = invalidLengthError{}
|
||||
|
||||
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||
func IsInvalidLengthError(err error) bool {
|
||||
_, ok := err.(invalidLengthError)
|
||||
return ok
|
||||
return errors.Is(err, ErrInvalidLength)
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
|
||||
@ -79,7 +101,7 @@ func Parse(s string) (UUID, error) {
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
return uuid, URNPrefixError{s[:9]}
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
@ -93,7 +115,7 @@ func Parse(s string) (UUID, error) {
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
@ -103,7 +125,8 @@ func Parse(s string) (UUID, error) {
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
@ -114,7 +137,7 @@ func Parse(s string) (UUID, error) {
|
||||
} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
@ -128,7 +151,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
return uuid, URNPrefixError{string(b[:9])}
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
@ -138,7 +161,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
@ -148,7 +171,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
@ -159,7 +182,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
return uuid, ErrInvalidUUIDFormat
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
@ -205,14 +228,14 @@ func Validate(s string) error {
|
||||
// UUID with "urn:uuid:" prefix
|
||||
case 36 + 9:
|
||||
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||
return fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
return URNPrefixError{s[:9]}
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// UUID enclosed in braces
|
||||
case 36 + 2:
|
||||
if s[0] != '{' || s[len(s)-1] != '}' {
|
||||
return fmt.Errorf("invalid bracketed UUID format")
|
||||
return ErrInvalidBracketedFormat
|
||||
}
|
||||
s = s[1 : len(s)-1]
|
||||
|
||||
@ -221,7 +244,7 @@ func Validate(s string) error {
|
||||
for i := 0; i < len(s); i += 2 {
|
||||
_, ok := xtob(s[i], s[i+1])
|
||||
if !ok {
|
||||
return errors.New("invalid UUID format")
|
||||
return ErrInvalidUUIDFormat
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,11 +255,11 @@ func Validate(s string) error {
|
||||
// Check for standard UUID format
|
||||
if len(s) == 36 {
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return errors.New("invalid UUID format")
|
||||
return ErrInvalidUUIDFormat
|
||||
}
|
||||
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
|
||||
if _, ok := xtob(s[x], s[x+1]); !ok {
|
||||
return errors.New("invalid UUID format")
|
||||
return ErrInvalidUUIDFormat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ func TestWrongLength(t *testing.T) {
|
||||
func TestIsWrongLength(t *testing.T) {
|
||||
_, err := Parse("12345")
|
||||
if !IsInvalidLengthError(err) {
|
||||
t.Errorf("expected error type is invalidLengthError")
|
||||
t.Errorf("IsInvalidLength returned incorrect type %T", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user