package auth import ( "testing" "time" ) func TestParseExpiration(t *testing.T) { tests := []struct { name string input string want time.Duration wantErr bool }{ {"30d", "30d", Expiration30Days, false}, {"30", "30", Expiration30Days, false}, {"60d", "60d", Expiration60Days, false}, {"60", "60", Expiration60Days, false}, {"90d", "90d", Expiration90Days, false}, {"90", "90", Expiration90Days, false}, {"1y", "1y", Expiration1Year, false}, {"1year", "1year", Expiration1Year, false}, {"365d", "365d", Expiration1Year, false}, {"never", "never", ExpirationNoLimit, false}, {"none", "none", ExpirationNoLimit, false}, {"empty", "", ExpirationNoLimit, false}, {"case insensitive", "30D", Expiration30Days, false}, {"invalid", "invalid", 0, true}, {"7d", "7d", 0, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseExpiration(tt.input) if (err != nil) != tt.wantErr { t.Errorf("ParseExpiration(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr) return } if got != tt.want { t.Errorf("ParseExpiration(%q) = %v, want %v", tt.input, got, tt.want) } }) } } func TestExpiresAt(t *testing.T) { t.Run("returns nil for zero duration", func(t *testing.T) { got := ExpiresAt(0) if got != nil { t.Errorf("ExpiresAt(0) = %v, want nil", got) } }) t.Run("returns future time for positive duration", func(t *testing.T) { before := time.Now() got := ExpiresAt(24 * time.Hour) after := time.Now() if got == nil { t.Fatal("ExpiresAt(24h) returned nil") } expectedMin := before.Add(24 * time.Hour) expectedMax := after.Add(24 * time.Hour) if got.Before(expectedMin) || got.After(expectedMax) { t.Errorf("ExpiresAt(24h) = %v, want between %v and %v", *got, expectedMin, expectedMax) } }) } func TestGenerateKey(t *testing.T) { t.Run("generates unique keys", func(t *testing.T) { key1, id1, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey() error = %v", err) } key2, id2, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey() error = %v", err) } if key1 == key2 { t.Error("Generated keys should be unique") } if id1 == id2 { t.Error("Generated identifiers should be unique") } }) t.Run("key has correct format", func(t *testing.T) { key, id, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey() error = %v", err) } if !ValidateKeyFormat(key) { t.Errorf("Generated key %q has invalid format", key) } if len(id) != KeyIdentifierLength { t.Errorf("Identifier length = %d, want %d", len(id), KeyIdentifierLength) } }) t.Run("key contains prefix and identifier", func(t *testing.T) { key, id, err := GenerateKey() if err != nil { t.Fatalf("GenerateKey() error = %v", err) } expectedPrefix := KeyPrefix + id + "_" if key[:len(expectedPrefix)] != expectedPrefix { t.Errorf("Key %q should start with %q", key, expectedPrefix) } }) } func TestHashKey(t *testing.T) { t.Run("produces consistent hash", func(t *testing.T) { key := "rdev_sk_abc12345_0123456789abcdef0123456789abcdef" hash1 := HashKey(key) hash2 := HashKey(key) if hash1 != hash2 { t.Error("Same key should produce same hash") } }) t.Run("different keys produce different hashes", func(t *testing.T) { hash1 := HashKey("key1") hash2 := HashKey("key2") if hash1 == hash2 { t.Error("Different keys should produce different hashes") } }) t.Run("hash is hex encoded", func(t *testing.T) { hash := HashKey("test") // SHA-256 produces 32 bytes = 64 hex characters if len(hash) != 64 { t.Errorf("Hash length = %d, want 64", len(hash)) } for _, c := range hash { if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { t.Errorf("Hash contains non-hex character: %c", c) } } }) } func TestValidateKeyFormat(t *testing.T) { tests := []struct { name string key string want bool }{ {"valid key", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef", true}, {"missing prefix", "abc12345_0123456789abcdef0123456789abcdef", false}, {"wrong prefix", "api_sk_abc12345_0123456789abcdef0123456789abcdef", false}, {"short identifier", "rdev_sk_abc1234_0123456789abcdef0123456789abcdef", false}, {"long identifier", "rdev_sk_abc123456_0123456789abcdef0123456789abcdef", false}, {"short random", "rdev_sk_abc12345_0123456789abcdef", false}, {"long random", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef00", false}, {"missing underscore", "rdev_sk_abc123450123456789abcdef0123456789abcdef", false}, {"extra underscore", "rdev_sk_abc12345_0123_456789abcdef0123456789abcdef", false}, {"empty", "", false}, {"only prefix", "rdev_sk_", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ValidateKeyFormat(tt.key); got != tt.want { t.Errorf("ValidateKeyFormat(%q) = %v, want %v", tt.key, got, tt.want) } }) } } func TestExtractPrefix(t *testing.T) { tests := []struct { name string key string want string }{ {"valid key", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef", "abc12345"}, {"missing prefix", "abc12345_random", ""}, {"only rdev_sk_", "rdev_sk_", ""}, {"empty", "", ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ExtractPrefix(tt.key); got != tt.want { t.Errorf("ExtractPrefix(%q) = %q, want %q", tt.key, got, tt.want) } }) } }