package config import ( "encoding/json" "os" "path/filepath" "strings" "testing" ) func TestSavePersistsRelativePaths(t *testing.T) { root := t.TempDir() cfg := defaults(root) cfg.Initialized = true cfg.ConfigPath = filepath.Join(root, "config.json") if err := Save(cfg); err != nil { t.Fatal(err) } data, err := os.ReadFile(filepath.Join(root, "config.json")) if err != nil { t.Fatal(err) } var saved Config if err := json.Unmarshal(data, &saved); err != nil { t.Fatal(err) } if saved.BaseDir != "." { t.Fatalf("BaseDir = %q, want relative dot", saved.BaseDir) } for name, value := range map[string]string{ "storage_dir": saved.StorageDir, "data_dir": saved.DataDir, "update_public_dir": saved.UpdatePublicDir, "update_notice_dir": saved.UpdateNoticeDir, "downloads_dir": saved.DownloadsDir, "sqlite_path": saved.Database.SQLitePath, } { if filepath.IsAbs(value) || strings.Contains(value, root) { t.Fatalf("%s saved as absolute path %q", name, value) } } } func TestPreflightCreatesRuntimeDirectoriesAndNoticeIndex(t *testing.T) { root := t.TempDir() cfg := defaults(root) checks := Preflight(cfg) for _, path := range []string{ cfg.UpdatePublicDir, cfg.UpdateNoticeDir, cfg.DownloadsDir, filepath.Join(cfg.UpdatePublicDir, "update-info.json"), filepath.Join(cfg.UpdatePublicDir, "media-types.json"), filepath.Join(cfg.UpdateNoticeDir, "total.json"), } { if _, err := os.Stat(path); err != nil { t.Fatalf("expected preflight to create %s: %v", path, err) } } for _, line := range FormatPreflight(cfg, checks) { if strings.Contains(line, root) { t.Fatalf("preflight line leaked absolute base path: %s", line) } } } func TestLoadRewritesAbsoluteConfigPaths(t *testing.T) { root := t.TempDir() t.Setenv("YMHUT_BASE_DIR", root) configPath := filepath.Join(root, "config.json") payload := map[string]any{ "initialized": true, "listen": ":33550", "storage_dir": filepath.Join(root, "storage"), "data_dir": filepath.Join(root, "data"), "update_public_dir": filepath.Join(root, "data", "update", "public"), "update_notice_dir": filepath.Join(root, "data", "update-notice"), "downloads_dir": filepath.Join(root, "data", "update", "public", "downloads"), "database": map[string]any{ "provider": "sqlite", "sqlite_path": filepath.Join(root, "storage", "unified.sqlite"), }, } data, err := json.Marshal(payload) if err != nil { t.Fatal(err) } if err := os.WriteFile(configPath, data, 0o600); err != nil { t.Fatal(err) } if _, err := Load(); err != nil { t.Fatal(err) } rewritten, err := os.ReadFile(configPath) if err != nil { t.Fatal(err) } if strings.Contains(string(rewritten), root) { t.Fatalf("config still contains absolute base path: %s", string(rewritten)) } }