Skip to content

Commit

Permalink
fix: broken backward compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
plusiv committed Aug 3, 2024
1 parent a0eddd2 commit 54f9572
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 24 deletions.
4 changes: 2 additions & 2 deletions json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ func TestJSONUnmarshal(t *testing.T) {
},
"empty": {
data: []byte(`{"ID1": ""}`),
expectedError: ErrInvalidLength,
expectedError: invalidLengthError{len: 0},
expectedResult: Nil,
},
"omitempty": {
data: []byte(`{"ID2": ""}`),
expectedError: ErrInvalidLength,
expectedError: invalidLengthError{len: 0},
expectedResult: Nil,
},
}
Expand Down
55 changes: 39 additions & 16 deletions uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,36 @@ var (
pool [randPoolSize]byte // protected with poolMu

ErrInvalidUUIDFormat = errors.New("invalid UUID format")
ErrInvalidURNPrefix = errors.New("invalid urn prefix")
ErrInvalidBracketedFormat = errors.New("invalid bracketed UUID format")
ErrInvalidLength = errors.New("invalid UUID length")
)

// IsInvalidLengthError is matcher function for custom error ErrInvalidLength
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 {
return errors.Is(err, ErrInvalidLength)
}
Expand All @@ -77,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("%w: %q", ErrInvalidURNPrefix, s[:9])
return uuid, URNPrefixError{s[:9]}
}
s = s[9:]

Expand All @@ -96,12 +120,13 @@ func Parse(s string) (UUID, error) {
}
return uuid, nil
default:
return uuid, fmt.Errorf("%w: %d", ErrInvalidLength, len(s))
return uuid, invalidLengthError{len(s)}
}
// 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, ErrInvalidUUIDFormat

}
for i, x := range [16]int{
0, 2, 4, 6,
Expand All @@ -126,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("%w: %q", ErrInvalidURNPrefix, b[:9])
return uuid, URNPrefixError{string(b[:9])}
}
b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
Expand All @@ -141,7 +166,7 @@ func ParseBytes(b []byte) (UUID, error) {
}
return uuid, nil
default:
return uuid, fmt.Errorf("%w: %d", ErrInvalidLength, len(b))
return uuid, invalidLengthError{len(b)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Expand Down Expand Up @@ -190,12 +215,10 @@ func Must(uuid UUID, err error) UUID {
}

// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
//
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
//
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
// It returns an error if the format is invalid, otherwise nil.
func Validate(s string) error {
switch len(s) {
Expand All @@ -205,7 +228,7 @@ func Validate(s string) error {
// UUID with "urn:uuid:" prefix
case 36 + 9:
if !strings.EqualFold(s[:9], "urn:uuid:") {
return fmt.Errorf("%w: %q", ErrInvalidURNPrefix, s[:9])
return URNPrefixError{s[:9]}
}
s = s[9:]

Expand All @@ -226,7 +249,7 @@ func Validate(s string) error {
}

default:
return fmt.Errorf("%w: %d", ErrInvalidLength, len(s))
return invalidLengthError{len(s)}
}

// Check for standard UUID format
Expand Down Expand Up @@ -362,7 +385,7 @@ type UUIDs []UUID

// Strings returns a string slice containing the string form of each UUID in uuids.
func (uuids UUIDs) Strings() []string {
uuidStrs := make([]string, len(uuids))
var uuidStrs = make([]string, len(uuids))
for i, uuid := range uuids {
uuidStrs[i] = uuid.String()
}
Expand Down
10 changes: 4 additions & 6 deletions uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 ErrInvalidLength")
t.Errorf("IsInvalidLength returned incorrect type %T", err)
}
}

Expand Down Expand Up @@ -634,10 +634,8 @@ func TestValidate(t *testing.T) {
}
}

var (
asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
asBytes = []byte(asString)
)
var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
var asBytes = []byte(asString)

func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
Expand Down Expand Up @@ -902,7 +900,7 @@ func TestVersion7Monotonicity(t *testing.T) {
type fakeRand struct{}

func (g fakeRand) Read(bs []byte) (int, error) {
for i := range bs {
for i, _ := range bs {
bs[i] = 0x88
}
return len(bs), nil
Expand Down

0 comments on commit 54f9572

Please sign in to comment.