@@ -0,0 +1,66 @@
+package config
+
+import (
+ "reflect"
+ "testing"
+)
+
+// TestSaveAndLoadConfig verifies that the config can be saved to and loaded from a file correctly.
+func TestSaveAndLoadConfig(t *testing.T) {
+ // Create a temporary directory for the test to avoid interfering with actual user config.
+ tempDir := t.TempDir()
+
+ // Temporarily override the user home directory to our temp directory.
+ // This ensures that our config file is written to a predictable, temporary location.
+ t.Setenv("HOME", tempDir)
+
+ // Define a sample configuration to save.
+ expectedConfig := &Config{
+ ServiceProvider: "gmail",
+ Email: "test@example.com",
+ Password: "supersecret",
+ Name: "Test User",
+ }
+
+ // Attempt to save the configuration.
+ err := SaveConfig(expectedConfig)
+ if err != nil {
+ t.Fatalf("SaveConfig() failed: %v", err)
+ }
+
+ // Attempt to load the configuration back.
+ loadedConfig, err := LoadConfig()
+ if err != nil {
+ t.Fatalf("LoadConfig() failed: %v", err)
+ }
+
+ // Compare the loaded configuration with the original one.
+ // reflect.DeepEqual is used for a deep comparison of the structs.
+ if !reflect.DeepEqual(loadedConfig, expectedConfig) {
+ t.Errorf("Loaded config does not match expected config.\nGot: %+v\nWant: %+v", loadedConfig, expectedConfig)
+ }
+}
+
+// TestIMAPServer tests the logic that determines the IMAP server address.
+func TestIMAPServer(t *testing.T) {
+ testCases := []struct {
+ name string
+ provider string
+ want string
+ }{
+ {"Gmail", "gmail", "imap.gmail.com"},
+ {"iCloud", "icloud", "imap.mail.me.com"},
+ {"Unsupported", "yahoo", ""},
+ {"Empty", "", ""},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ cfg := &Config{ServiceProvider: tc.provider}
+ got := cfg.IMAPServer()
+ if got != tc.want {
+ t.Errorf("IMAPServer() = %q, want %q", got, tc.want)
+ }
+ })
+ }
+}
@@ -0,0 +1,45 @@
+package sender
+
+import (
+ "strings"
+ "testing"
+)
+
+// TestGenerateMessageID ensures the Message-ID has the correct format.
+func TestGenerateMessageID(t *testing.T) {
+ from := "test@example.com"
+ msgID := generateMessageID(from)
+
+ // Check if the message ID is enclosed in angle brackets.
+ if !strings.HasPrefix(msgID, "<") || !strings.HasSuffix(msgID, ">") {
+ t.Errorf("Message-ID should be enclosed in angle brackets, got %s", msgID)
+ }
+
+ // Check if the 'from' address is part of the message ID.
+ if !strings.Contains(msgID, from) {
+ t.Errorf("Message-ID should contain the from address, got %s", msgID)
+ }
+
+ // The original check was too simple and failed because the 'from' address itself contains an '@'.
+ // A Message-ID is generally <unique-part@domain>. The current implementation uses the full 'from' address as the domain part.
+ // This revised check validates that structure correctly.
+ unwrappedID := strings.Trim(msgID, "<>")
+
+ // Ensure there's at least one '@' symbol.
+ if !strings.Contains(unwrappedID, "@") {
+ t.Errorf("Message-ID should contain an '@' symbol, got %s", msgID)
+ }
+
+ // Check that the ID ends with the full 'from' address, preceded by an '@'.
+ // This confirms the structure is <random_part>@<from_address>.
+ expectedSuffix := "@" + from
+ if !strings.HasSuffix(unwrappedID, expectedSuffix) {
+ t.Errorf("Message-ID should end with '@' + from address. Got %s, expected suffix %s", unwrappedID, expectedSuffix)
+ }
+
+ // Check that the part before the suffix is not empty.
+ randomPart := strings.TrimSuffix(unwrappedID, expectedSuffix)
+ if randomPart == "" {
+ t.Errorf("Message-ID has an empty random part, got %s", msgID)
+ }
+}