package config import ( "os" "path/filepath" "strings" "testing" ) func TestGenerateAndLoadRoundTrip(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "settings.ini") cfg, err := Load(path) if err != nil { t.Fatalf("Load (generate): %v", err) } if _, err := os.Stat(path); err != nil { t.Fatalf("settings.ini was not written: %v", err) } if got := cfg.Section("Server").Key("SMTP_PORT").String(); got != "25" { t.Errorf("SMTP_PORT = %q, want 25", got) } if got := cfg.Section("Attachments").Key("attachments_path").String(); got == "" { t.Error("Attachments.attachments_path default is missing (the approved bug fix)") } // Load again against the now-existing file — must not regenerate/overwrite. cfg2, err := Load(path) if err != nil { t.Fatalf("Load (existing): %v", err) } if got := cfg2.Section("Server").Key("SMTP_PORT").String(); got != "25" { t.Errorf("second Load: SMTP_PORT = %q, want 25", got) } } func TestLoadBackfillsMissingKeysWithoutTouchingExistingValues(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "settings.ini") // Simulate an older settings.ini written before [LetsEncryptHTTP] and [TLS]'s // *_cert keys existed, with a deliberately non-default value on a key that IS // already present — Load must never touch that. old := "[Server]\nHOSTNAME = old.example.com\n\n[TLS]\ntls_cert_file = custom/path.crt\n" if err := os.WriteFile(path, []byte(old), 0o644); err != nil { t.Fatal(err) } cfg, err := Load(path) if err != nil { t.Fatalf("Load: %v", err) } if got := cfg.Section("Server").Key("HOSTNAME").String(); got != "old.example.com" { t.Errorf("existing value clobbered: HOSTNAME = %q", got) } if got := cfg.Section("TLS").Key("tls_cert_file").String(); got != "custom/path.crt" { t.Errorf("existing value clobbered: tls_cert_file = %q", got) } if got := cfg.Section("TLS").Key("smtp_tls_cert").String(); got != "custom" { t.Errorf("smtp_tls_cert not backfilled: got %q, want default %q", got, "custom") } if !cfg.Section("LetsEncryptHTTP").HasKey("enabled") { t.Error("[LetsEncryptHTTP] section was not backfilled") } // The backfill must be persisted to disk, not just held in memory. raw, err := os.ReadFile(path) if err != nil { t.Fatal(err) } if !strings.Contains(string(raw), "smtp_tls_cert") { t.Error("backfilled key was not saved back to settings.ini") } } func TestAbsoluteSQLitePath(t *testing.T) { cases := []struct{ url, root, want string }{ {"sqlite:///server_data/db.sqlite", "/app", "/app/server_data/db.sqlite"}, {"sqlite:////abs/db.sqlite", "/app", "/abs/db.sqlite"}, {"mysql://x", "/app", "mysql://x"}, } for _, c := range cases { if got := AbsoluteSQLitePath(c.url, c.root); got != c.want { t.Errorf("AbsoluteSQLitePath(%q, %q) = %q, want %q", c.url, c.root, got, c.want) } } }