2026-01-04 20:59:26 +00:00
|
|
|
package imap
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"log/slog"
|
|
|
|
|
"testing"
|
|
|
|
|
|
2026-01-05 01:29:32 +00:00
|
|
|
"github.com/chimerical-llc/raven/internal/filter"
|
2026-01-04 20:59:26 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestConfigAddress(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
cfg Config
|
|
|
|
|
want string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "standard config",
|
|
|
|
|
cfg: Config{Host: "imap.example.com", Port: "993"},
|
|
|
|
|
want: "imap.example.com:993",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "empty host",
|
|
|
|
|
cfg: Config{Host: "", Port: "993"},
|
|
|
|
|
want: ":993",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "empty port",
|
|
|
|
|
cfg: Config{Host: "imap.example.com", Port: ""},
|
|
|
|
|
want: "imap.example.com:",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
if got := tt.cfg.Address(); got != tt.want {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"Address() = %q, want %q",
|
|
|
|
|
got, tt.want,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestConfigValidate(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
cfg Config
|
|
|
|
|
wantErr string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "valid config",
|
|
|
|
|
cfg: Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Password: "secret",
|
|
|
|
|
Port: "993",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
},
|
|
|
|
|
wantErr: "",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing host",
|
|
|
|
|
cfg: Config{
|
|
|
|
|
Password: "secret",
|
|
|
|
|
Port: "993",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
},
|
|
|
|
|
wantErr: "missing host",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing password",
|
|
|
|
|
cfg: Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Port: "993",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
},
|
|
|
|
|
wantErr: "missing password",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing port",
|
|
|
|
|
cfg: Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Password: "secret",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
},
|
|
|
|
|
wantErr: "missing port",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing user",
|
|
|
|
|
cfg: Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Password: "secret",
|
|
|
|
|
Port: "993",
|
|
|
|
|
},
|
|
|
|
|
wantErr: "missing user",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
err := tt.cfg.Validate()
|
|
|
|
|
if tt.wantErr == "" {
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"Validate() unexpected error: %v",
|
|
|
|
|
err,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"Validate() expected error containing %q, got nil",
|
|
|
|
|
tt.wantErr,
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if got := err.Error(); got != tt.wantErr {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"Validate() error = %q, want %q",
|
|
|
|
|
got, tt.wantErr,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNewClient(t *testing.T) {
|
|
|
|
|
validCfg := Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Password: "secret",
|
|
|
|
|
Port: "993",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
cfg Config
|
|
|
|
|
filters filter.Filters
|
|
|
|
|
wantErr bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "valid config",
|
|
|
|
|
cfg: validCfg,
|
|
|
|
|
filters: filter.Filters{},
|
|
|
|
|
wantErr: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "valid config with filters",
|
|
|
|
|
cfg: validCfg,
|
|
|
|
|
filters: filter.Filters{
|
|
|
|
|
Subject: "test",
|
|
|
|
|
To: "recipient@example.com",
|
|
|
|
|
Body: []string{"keyword"},
|
|
|
|
|
},
|
|
|
|
|
wantErr: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "invalid config",
|
|
|
|
|
cfg: Config{Host: "imap.example.com"},
|
|
|
|
|
filters: filter.Filters{},
|
|
|
|
|
wantErr: true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
client, err := NewClient(
|
|
|
|
|
tt.cfg, tt.filters, slog.Default(),
|
|
|
|
|
)
|
|
|
|
|
if tt.wantErr {
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Error(
|
|
|
|
|
"NewClient() expected error, got nil",
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"NewClient() unexpected error: %v", err,
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if client == nil {
|
|
|
|
|
t.Error("NewClient() returned nil client")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// Verify client is not connected.
|
|
|
|
|
if client.Client() != nil {
|
|
|
|
|
t.Error(
|
|
|
|
|
"NewClient() client should not be connected",
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestClientNotConnected(t *testing.T) {
|
|
|
|
|
cfg := Config{
|
|
|
|
|
Host: "imap.example.com",
|
|
|
|
|
Password: "secret",
|
|
|
|
|
Port: "993",
|
|
|
|
|
User: "user@example.com",
|
|
|
|
|
}
|
|
|
|
|
client, err := NewClient(cfg, filter.Filters{}, slog.Default())
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("NewClient() unexpected error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Run("Fetch without connection", func(t *testing.T) {
|
|
|
|
|
_, err := client.Fetch(1, true)
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Error("Fetch() expected error when not connected")
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("MarkSeen without connection", func(t *testing.T) {
|
|
|
|
|
err := client.MarkSeen(1)
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Error("MarkSeen() expected error when not connected")
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|