From b0e4f0077f896ae75e5832bcd3c4569be6cf1a39 Mon Sep 17 00:00:00 2001 From: Aivars Sterns Date: Fri, 7 Nov 2025 08:50:07 +0200 Subject: [PATCH] fix: add tests --- aliases_test.go | 315 ++++++++++++++++++++++++++++++++++++++++++++++++ smtp.go | 2 +- 2 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 aliases_test.go diff --git a/aliases_test.go b/aliases_test.go new file mode 100644 index 0000000..dff13e6 --- /dev/null +++ b/aliases_test.go @@ -0,0 +1,315 @@ +package main + +import ( + "io" + "os" + "testing" + + "github.com/rs/zerolog" +) + +func init() { + // Initialize logger for tests to prevent nil pointer dereference + logger := zerolog.New(io.Discard).With().Timestamp().Logger() + log = &logger +} +func TestAliasLoadFile(t *testing.T) { + tests := []struct { + name string + content string + expected AliasMap + expectError bool + }{ + { + name: "valid aliases", + content: "user1 alias1\nuser2 alias2\nuser3 alias3", + expected: AliasMap{ + "user1": "alias1", + "user2": "alias2", + "user3": "alias3", + }, + expectError: false, + }, + { + name: "empty file", + content: "", + expected: AliasMap{}, + expectError: false, + }, + { + name: "file with empty lines", + content: "user1 alias1\n\nuser2 alias2\n\n", + expected: AliasMap{ + "user1": "alias1", + "user2": "alias2", + }, + expectError: false, + }, + { + name: "file with whitespace", + content: " user1 alias1 \n\t user2\talias2\t", + expected: AliasMap{ + "user1": "alias1", + "user2": "alias2", + }, + expectError: false, + }, + { + name: "extra fields ignored", + content: "user1 alias1 extra field\nuser2 alias2", + expected: AliasMap{ + "user1": "alias1", + "user2": "alias2", + }, + expectError: false, + }, + { + name: "single field line ignored", + content: "user1\nuser2 alias2", + expected: AliasMap{"user2": "alias2"}, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + if _, err := tmpFile.WriteString(tt.content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + result, err := AliasLoadFile(tmpFile.Name()) + + if tt.expectError && err == nil { + t.Error("expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(result) != len(tt.expected) { + t.Errorf("expected %d aliases, got %d", len(tt.expected), len(result)) + } + + for key, expectedValue := range tt.expected { + if actualValue, exists := result[key]; !exists { + t.Errorf("expected key %q not found", key) + } else if actualValue != expectedValue { + t.Errorf("for key %q: expected %q, got %q", key, expectedValue, actualValue) + } + } + }) + } +} + +func TestLoadAliases(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + content := "user1 alias1\nuser2 alias2" + if _, err := tmpFile.WriteString(content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + err = LoadAliases(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + aliasesMutex.RLock() + defer aliasesMutex.RUnlock() + + if len(aliasesList) != 2 { + t.Errorf("expected 2 aliases, got %d", len(aliasesList)) + } + + if aliasesList["user1"] != "alias1" { + t.Errorf("expected user1 -> alias1, got %q", aliasesList["user1"]) + } + if aliasesList["user2"] != "alias2" { + t.Errorf("expected user2 -> alias2, got %q", aliasesList["user2"]) + } +} + +func TestLoadAliases_EmptyFile(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + tmpFile.Close() + + err = LoadAliases(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + aliasesMutex.RLock() + defer aliasesMutex.RUnlock() + + if len(aliasesList) != 0 { + t.Errorf("expected 0 aliases, got %d", len(aliasesList)) + } +} + +func TestLoadAliases_UpdatesExistingAliases(t *testing.T) { + // First load + tmpFile1, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile1.Name()) + + content1 := "user1 alias1\nuser2 alias2" + if _, err := tmpFile1.WriteString(content1); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile1.Close() + + err = LoadAliases(tmpFile1.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Second load with different content + tmpFile2, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile2.Name()) + + content2 := "user3 alias3" + if _, err := tmpFile2.WriteString(content2); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile2.Close() + + err = LoadAliases(tmpFile2.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + aliasesMutex.RLock() + defer aliasesMutex.RUnlock() + + if len(aliasesList) != 1 { + t.Errorf("expected 1 alias after reload, got %d", len(aliasesList)) + } + + if aliasesList["user3"] != "alias3" { + t.Errorf("expected user3 -> alias3, got %q", aliasesList["user3"]) + } + + if _, exists := aliasesList["user1"]; exists { + t.Error("expected user1 to be removed after reload") + } +} + +func TestAliasLoadFile_MultipleSpaces(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + content := "user1 alias1\nuser2 alias2" + if _, err := tmpFile.WriteString(content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + result, err := AliasLoadFile(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if result["user1"] != "alias1" { + t.Errorf("expected user1 -> alias1, got %q", result["user1"]) + } + if result["user2"] != "alias2" { + t.Errorf("expected user2 -> alias2, got %q", result["user2"]) + } +} + +func TestAliasLoadFile_TabSeparated(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + content := "user1\talias1\nuser2\t\talias2" + if _, err := tmpFile.WriteString(content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + result, err := AliasLoadFile(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(result) != 2 { + t.Errorf("expected 2 aliases, got %d", len(result)) + } +} + +func TestAliasLoadFile_DuplicateKeys(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + content := "user1 alias1\nuser1 alias2\nuser1 alias3" + if _, err := tmpFile.WriteString(content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + result, err := AliasLoadFile(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(result) != 1 { + t.Errorf("expected 1 alias (last one wins), got %d", len(result)) + } + + if result["user1"] != "alias3" { + t.Errorf("expected user1 -> alias3 (last one), got %q", result["user1"]) + } +} + +func TestAliasLoadFile_OnlyWhitespace(t *testing.T) { + tmpFile, err := os.CreateTemp("", "aliases-*.txt") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + content := " \n\t\t\n \t \n" + if _, err := tmpFile.WriteString(content); err != nil { + t.Fatalf("failed to write to temp file: %v", err) + } + tmpFile.Close() + + result, err := AliasLoadFile(tmpFile.Name()) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(result) != 0 { + t.Errorf("expected 0 aliases, got %d", len(result)) + } +} diff --git a/smtp.go b/smtp.go index bee2bf1..628e124 100644 --- a/smtp.go +++ b/smtp.go @@ -200,7 +200,7 @@ func (c *Client) Auth(a smtp.Auth) error { return err } encoding := base64.StdEncoding - mech, resp, err := a.Start(&smtp.ServerInfo{Name: c.serverName, TLS: c.tls, Auth: c.auth}) + mech, resp, err := a.Start(&smtp.ServerInfo{c.serverName, c.tls, c.auth}) if err != nil { c.Quit() return err