Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented support for checkable errors (#131)
- Loading branch information
Showing
6 changed files
with
260 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package uuid | ||
|
||
// Error is a custom error type for UUID-related errors | ||
type Error string | ||
|
||
// The strings defined in the errors is matching the previous behavior before | ||
// the custom error type was implemented. The reason is that some people might | ||
// be relying on the exact string representation to handle errors in their code. | ||
const ( | ||
// ErrInvalidFormat is returned when the UUID string representation does not | ||
// match the expected format. See also ErrIncorrectFormatInString. | ||
ErrInvalidFormat = Error("uuid: invalid UUID format") | ||
|
||
// ErrIncorrectFormatInString can be returned instead of ErrInvalidFormat. | ||
// A separate error type is used because of how errors used to be formatted | ||
// before custom error types were introduced. | ||
ErrIncorrectFormatInString = Error("uuid: incorrect UUID format in string") | ||
|
||
// ErrIncorrectLength is returned when the UUID does not have the | ||
// appropriate string length for parsing the UUID. | ||
ErrIncorrectLength = Error("uuid: incorrect UUID length") | ||
|
||
// ErrIncorrectByteLength indicates the UUID byte slice length is invalid. | ||
ErrIncorrectByteLength = Error("uuid: UUID must be exactly 16 bytes long") | ||
|
||
// ErrNoHwAddressFound is returned when a hardware (MAC) address cannot be | ||
// found for UUID generation. | ||
ErrNoHwAddressFound = Error("uuid: no HW address found") | ||
|
||
// ErrTypeConvertError is returned for type conversion operation fails. | ||
ErrTypeConvertError = Error("uuid: cannot convert") | ||
|
||
// ErrInvalidVersion indicates an unsupported or invalid UUID version. | ||
ErrInvalidVersion = Error("uuid:") | ||
) | ||
|
||
// Error returns the string representation of the UUID error. | ||
func (e Error) Error() string { | ||
return string(e) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
package uuid | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net" | ||
"testing" | ||
) | ||
|
||
func TestIsAsError(t *testing.T) { | ||
tcs := []struct { | ||
err error | ||
expected string | ||
expectedErr error | ||
}{ | ||
{ | ||
err: fmt.Errorf("%w sample error: %v", ErrInvalidVersion, 123), | ||
expected: "uuid: sample error: 123", | ||
expectedErr: ErrInvalidVersion, | ||
}, | ||
{ | ||
err: fmt.Errorf("%w", ErrInvalidFormat), | ||
expected: "uuid: invalid UUID format", | ||
expectedErr: ErrInvalidFormat, | ||
}, | ||
{ | ||
err: fmt.Errorf("%w %q", ErrIncorrectFormatInString, "test"), | ||
expected: "uuid: incorrect UUID format in string \"test\"", | ||
expectedErr: ErrIncorrectFormatInString, | ||
}, | ||
} | ||
for i, tc := range tcs { | ||
t.Run(fmt.Sprintf("Test case %d", i), func(t *testing.T) { | ||
if tc.err.Error() != tc.expected { | ||
t.Errorf("expected err.Error() to be '%s' but was '%s'", tc.expected, tc.err.Error()) | ||
} | ||
var uuidErr Error | ||
if !errors.As(tc.err, &uuidErr) { | ||
t.Error("expected errors.As() to work") | ||
} | ||
if !errors.Is(tc.err, tc.expectedErr) { | ||
t.Errorf("expected error to be, or wrap, the %v sentinel error", tc.expectedErr) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestParseErrors(t *testing.T) { | ||
tcs := []struct { | ||
function string | ||
uuidStr string | ||
expected string | ||
}{ | ||
{ // 34 chars - With brackets | ||
function: "parse", | ||
uuidStr: "..................................", | ||
expected: "uuid: incorrect UUID format in string \"..................................\"", | ||
}, | ||
{ // 41 chars - urn:uuid: | ||
function: "parse", | ||
uuidStr: "123456789................................", | ||
expected: "uuid: incorrect UUID format in string \"123456789\"", | ||
}, | ||
{ // other | ||
function: "parse", | ||
uuidStr: "....", | ||
expected: "uuid: incorrect UUID length 4 in string \"....\"", | ||
}, | ||
{ // 36 chars - canonical, but not correct format | ||
function: "parse", | ||
uuidStr: "....................................", | ||
expected: "uuid: incorrect UUID format in string \"....................................\"", | ||
}, | ||
{ // 36 chars - canonical, invalid data | ||
function: "parse", | ||
uuidStr: "xx00ae9e-dae3-459f-ad0e-6b574be3f950", | ||
expected: "uuid: invalid UUID format", | ||
}, | ||
{ // Hash like | ||
function: "parse", | ||
uuidStr: "................................", | ||
expected: "uuid: invalid UUID format", | ||
}, | ||
{ // Hash like, invalid | ||
function: "parse", | ||
uuidStr: "xx00ae9edae3459fad0e6b574be3f950", | ||
expected: "uuid: invalid UUID format", | ||
}, | ||
{ // Hash like, invalid | ||
function: "parse", | ||
uuidStr: "xx00ae9edae3459fad0e6b574be3f950", | ||
expected: "uuid: invalid UUID format", | ||
}, | ||
} | ||
for i, tc := range tcs { | ||
t.Run(fmt.Sprintf("Test case %d", i), func(t *testing.T) { | ||
id := UUID{} | ||
err := id.Parse(tc.uuidStr) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
if err.Error() != tc.expected { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), tc.expected) | ||
} | ||
err = id.UnmarshalText([]byte(tc.uuidStr)) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
if err.Error() != tc.expected { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), tc.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestUnmarshalBinaryError(t *testing.T) { | ||
id := UUID{} | ||
b := make([]byte, 33) | ||
expectedErr := "uuid: UUID must be exactly 16 bytes long, got 33 bytes" | ||
err := id.UnmarshalBinary([]byte(b)) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
} | ||
|
||
func TestScanError(t *testing.T) { | ||
id := UUID{} | ||
err := id.Scan(123) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
expectedErr := "uuid: cannot convert int to UUID" | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
} | ||
|
||
func TestUUIDVersionErrors(t *testing.T) { | ||
// UUId V1 Version | ||
id := FromStringOrNil("e86160d3-beff-443c-b9b5-1f8197ccb12e") | ||
_, err := TimestampFromV1(id) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
expectedErr := "uuid: e86160d3-beff-443c-b9b5-1f8197ccb12e is version 4, not version 1" | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
|
||
// UUId V2 Version | ||
id = FromStringOrNil("e86160d3-beff-443c-b9b5-1f8197ccb12e") | ||
_, err = TimestampFromV6(id) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
expectedErr = "uuid: e86160d3-beff-443c-b9b5-1f8197ccb12e is version 4, not version 6" | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
|
||
// UUId V7 Version | ||
id = FromStringOrNil("e86160d3-beff-443c-b9b5-1f8197ccb12e") | ||
_, err = TimestampFromV7(id) | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
expectedErr = "uuid: e86160d3-beff-443c-b9b5-1f8197ccb12e is version 4, not version 7" | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
} | ||
|
||
// This test cannot be run in parallel with other tests since it modifies the | ||
// global state | ||
func TestErrNoHwAddressFound(t *testing.T) { | ||
netInterfaces = func() ([]net.Interface, error) { | ||
return nil, nil | ||
} | ||
defer func() { | ||
netInterfaces = net.Interfaces | ||
}() | ||
_, err := defaultHWAddrFunc() | ||
if err == nil { | ||
t.Error("expected an error") | ||
return | ||
} | ||
expectedErr := "uuid: no HW address found" | ||
if err.Error() != expectedErr { | ||
t.Errorf("unexpected error '%s' != '%s'", err.Error(), expectedErr) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.