package infra import ( "strings" "testing" "golang.org/x/crypto/bcrypt" ) func TestBcryptHtpasswd(t *testing.T) { t.Run("hash valido pasa CompareHashAndPassword", func(t *testing.T) { line, err := BcryptHtpasswd("lucas", "s3cr3t", 4) if err != nil { t.Fatalf("unexpected error: %v", err) } parts := strings.SplitN(line, ":", 2) if len(parts) != 2 { t.Fatalf("expected user:hash, got %q", line) } if err := bcrypt.CompareHashAndPassword([]byte(parts[1]), []byte("s3cr3t")); err != nil { t.Errorf("hash does not match password: %v", err) } }) t.Run("formato es user:hash", func(t *testing.T) { line, err := BcryptHtpasswd("admin", "pass", 4) if err != nil { t.Fatalf("unexpected error: %v", err) } if !strings.HasPrefix(line, "admin:") { t.Errorf("expected line to start with 'admin:', got %q", line) } parts := strings.SplitN(line, ":", 2) if len(parts) != 2 || parts[1] == "" { t.Errorf("expected non-empty hash after colon, got %q", line) } }) t.Run("cost cero usa default 10", func(t *testing.T) { line, err := BcryptHtpasswd("user", "password", 0) if err != nil { t.Fatalf("unexpected error: %v", err) } parts := strings.SplitN(line, ":", 2) cost, err := bcrypt.Cost([]byte(parts[1])) if err != nil { t.Fatalf("could not extract cost: %v", err) } if cost != 10 { t.Errorf("expected cost 10, got %d", cost) } }) t.Run("error si user vacio", func(t *testing.T) { _, err := BcryptHtpasswd("", "pass", 4) if err == nil { t.Error("expected error for empty user, got nil") } }) t.Run("error si password vacio", func(t *testing.T) { _, err := BcryptHtpasswd("user", "", 4) if err == nil { t.Error("expected error for empty password, got nil") } }) t.Run("error si cost fuera de rango", func(t *testing.T) { _, err := BcryptHtpasswd("user", "pass", 32) if err == nil { t.Error("expected error for cost=32, got nil") } _, err = BcryptHtpasswd("user", "pass", 3) if err == nil { t.Error("expected error for cost=3, got nil") } }) }