diff --git a/helper.go b/helper.go index 169c53a..70e9952 100644 --- a/helper.go +++ b/helper.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "errors" "fmt" - "strings" ) // Helper function to encode timestamp into the UUID byte array. @@ -29,14 +28,32 @@ func decodeTimestamp(uuidBytes []byte) uint64 { uint64(uuidBytes[3])<<16 | uint64(uuidBytes[4])<<8 | uint64(uuidBytes[5]) } +// Helper function to parse and sanitize a UUID string. // Helper function to parse and sanitize a UUID string. func parseUUID(uuid string) ([]byte, error) { - uuid = strings.ReplaceAll(uuid, "-", "") - if len(uuid) != 32 { + switch len(uuid) { + case 32: + // Fast path for UUIDs without dashes + return hex.DecodeString(uuid) + case 36: + // Validate dash positions + if uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' || uuid[23] != '-' { + return nil, errors.New("invalid UUID format") + } + + // Remove dashes while copying characters + result := make([]byte, 32) + j := 0 + for i := 0; i < len(uuid); i++ { + if uuid[i] != '-' { + result[j] = uuid[i] + j++ + } + } + return hex.DecodeString(string(result)) + default: return nil, errors.New("invalid UUID length") } - - return hex.DecodeString(uuid) } // Helper function to check if a UUID is all zeros. diff --git a/uuidv8_test.go b/uuidv8_test.go index 34c379d..e9ef3e3 100644 --- a/uuidv8_test.go +++ b/uuidv8_test.go @@ -720,3 +720,75 @@ func TestUUIDv8_Scan_EdgeCases(t *testing.T) { }) } } + +func TestFromString_InvalidInputs(t *testing.T) { + tests := []string{ + "123", // Too short + "123e4567e89b12d3a4564266141740000000", // Too long + "123e4567e89b12d3a45642661417400g", // Invalid character + "123e-4567-e89b-12d3-a456-426614174000", // Misplaced dashes + "123e4567-e89b-12d3-a456-426614174000-", // Extra dash at the end + "--123e4567-e89b-12d3-a456-426614174000", // Extra dash at the start + "123e4567-e89b-12d3-a456-42-6614174000", // Randomly placed dash + "------------------------------------", // 36 dashes + "9a3d4049-0e2c-8080-0102-030405060000", // Valid UUID with dashes + } + + for _, input := range tests { + t.Run("Testing UUID: "+input, func(t *testing.T) { + _, err := uuidv8.FromString(input) + // The last case is valid; others should fail + if input == "9a3d4049-0e2c-8080-0102-030405060000" { + if err != nil { + t.Errorf("Expected valid UUID but got error for input: %s", input) + } + } else { + if err == nil { + t.Errorf("Expected error, got nil for input: %s", input) + } + } + }) + } +} + +func TestFromStringOrNil_InvalidInputs(t *testing.T) { + tests := []string{ + "123", // Too short + "123e4567e89b12d3a4564266141740000000", // Too long + "123e4567e89b12d3a45642661417400g", // Invalid character + "", // Empty string + "123e4567-e89b-12d3-a456-426614174000-", // Extra dash at the end + "--123e4567-e89b-12d3-a456-426614174000", // Extra dash at the start + "123e4567-e89b-12d3-a456-42-6614174000", // Randomly placed dash + } + + for _, input := range tests { + t.Run("Invalid UUID "+input, func(t *testing.T) { + result := uuidv8.FromStringOrNil(input) + if result != nil { + t.Errorf("Expected nil for input: %s, got %v", input, result) + } + }) + } +} + +func TestIsValidUUIDv8_InvalidUUIDs(t *testing.T) { + invalidUUIDs := []string{ + "123", // Too short + "123e4567e89b12d3a4564266141740000000", // Too long + "123e4567e89b12d3a45642661417400g", // Invalid character + "", // Empty string + "123e4567-e89b-12d3-a456-426614174000-", // Extra dash at the end + "--123e4567-e89b-12d3-a456-426614174000", // Extra dash at the start + "123e4567-e89b-12d3-a456-42-6614174000", // Randomly placed dash + + } + + for _, uuid := range invalidUUIDs { + t.Run("Invalid UUID "+uuid, func(t *testing.T) { + if uuidv8.IsValidUUIDv8(uuid) { + t.Errorf("Expected UUID %s to be invalid", uuid) + } + }) + } +}