From 6ab7ccb7a16cedbb9dffb9c9a547c6eca8e31a76 Mon Sep 17 00:00:00 2001 From: Romain Bertrand Date: Mon, 8 Dec 2025 10:14:47 +0100 Subject: [PATCH] test: add some unit tests --- internal/api/client_test.go | 28 ++++ internal/config/config.go | 6 + internal/config/config_test.go | 229 +++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 internal/api/client_test.go create mode 100644 internal/config/config_test.go diff --git a/internal/api/client_test.go b/internal/api/client_test.go new file mode 100644 index 0000000..951a25b --- /dev/null +++ b/internal/api/client_test.go @@ -0,0 +1,28 @@ +package api + +import ( + "testing" + + "codeberg.org/romaintb/fgj/internal/config" +) + +func TestClient_Hostname(t *testing.T) { + client := &Client{ + hostname: "codeberg.org", + } + + if client.Hostname() != "codeberg.org" { + t.Errorf("Expected hostname 'codeberg.org', got '%s'", client.Hostname()) + } +} + +func TestNewClientFromConfig_MissingHost(t *testing.T) { + cfg := &config.Config{ + Hosts: map[string]config.HostConfig{}, + } + + _, err := NewClientFromConfig(cfg, "nonexistent.org") + if err == nil { + t.Error("Expected error for nonexistent host") + } +} diff --git a/internal/config/config.go b/internal/config/config.go index 32f80ae..41c7409 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -41,7 +41,10 @@ func Load() (*Config, error) { if err != nil { return nil, err } + return LoadFromPath(path) +} +func LoadFromPath(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { @@ -67,7 +70,10 @@ func (c *Config) Save() error { if err != nil { return err } + return c.SaveToPath(path) +} +func (c *Config) SaveToPath(path string) error { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0755); err != nil { return err diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..90970b0 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,229 @@ +package config + +import ( + "os" + "path/filepath" + "testing" +) + +func TestConfig_SetHost(t *testing.T) { + cfg := &Config{} + + hostConfig := HostConfig{ + Hostname: "codeberg.org", + Token: "test-token", + User: "testuser", + } + + cfg.SetHost("codeberg.org", hostConfig) + + if cfg.Hosts == nil { + t.Fatal("Hosts map should not be nil") + } + + if len(cfg.Hosts) != 1 { + t.Errorf("Expected 1 host, got %d", len(cfg.Hosts)) + } + + host, ok := cfg.Hosts["codeberg.org"] + if !ok { + t.Fatal("Host codeberg.org not found") + } + + if host.Hostname != "codeberg.org" { + t.Errorf("Expected hostname 'codeberg.org', got '%s'", host.Hostname) + } + + if host.Token != "test-token" { + t.Errorf("Expected token 'test-token', got '%s'", host.Token) + } +} + +func TestConfig_GetHost(t *testing.T) { + cfg := &Config{ + Hosts: map[string]HostConfig{ + "codeberg.org": { + Hostname: "codeberg.org", + Token: "test-token", + }, + }, + } + + host, err := cfg.GetHost("codeberg.org") + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if host.Hostname != "codeberg.org" { + t.Errorf("Expected hostname 'codeberg.org', got '%s'", host.Hostname) + } + + _, err = cfg.GetHost("nonexistent.org") + if err == nil { + t.Error("Expected error for nonexistent host") + } +} + +func TestGetConfigDir(t *testing.T) { + dir, err := GetConfigDir() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if dir == "" { + t.Error("Config directory should not be empty") + } +} + +func TestGetConfigPath(t *testing.T) { + path, err := GetConfigPath() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if path == "" { + t.Error("Config path should not be empty") + } +} + +func TestConfig_SaveAndLoad(t *testing.T) { + // Create a temp directory for testing + tempDir := t.TempDir() + tempFile := filepath.Join(tempDir, "config.yaml") + + // Create a config with test data + cfg := &Config{ + Hosts: map[string]HostConfig{ + "codeberg.org": { + Hostname: "codeberg.org", + Token: "test-token-123", + User: "testuser", + GitProtocol: "ssh", + }, + "github.com": { + Hostname: "github.com", + Token: "github-token-456", + User: "githubuser", + GitProtocol: "https", + }, + }, + } + + // Test Save + err := cfg.SaveToPath(tempFile) + if err != nil { + t.Fatalf("Failed to save config: %v", err) + } + + // Verify file exists + if _, err := os.Stat(tempFile); os.IsNotExist(err) { + t.Fatal("Config file was not created") + } + + // Test Load + loadedCfg, err := LoadFromPath(tempFile) + if err != nil { + t.Fatalf("Failed to load config: %v", err) + } + + // Verify loaded config matches saved config + if len(loadedCfg.Hosts) != 2 { + t.Errorf("Expected 2 hosts, got %d", len(loadedCfg.Hosts)) + } + + // Check codeberg.org host + codebergHost, ok := loadedCfg.Hosts["codeberg.org"] + if !ok { + t.Fatal("codeberg.org host not found in loaded config") + } + if codebergHost.Token != "test-token-123" { + t.Errorf("Expected token 'test-token-123', got '%s'", codebergHost.Token) + } + if codebergHost.User != "testuser" { + t.Errorf("Expected user 'testuser', got '%s'", codebergHost.User) + } + if codebergHost.GitProtocol != "ssh" { + t.Errorf("Expected git_protocol 'ssh', got '%s'", codebergHost.GitProtocol) + } + + // Check github.com host + githubHost, ok := loadedCfg.Hosts["github.com"] + if !ok { + t.Fatal("github.com host not found in loaded config") + } + if githubHost.Token != "github-token-456" { + t.Errorf("Expected token 'github-token-456', got '%s'", githubHost.Token) + } +} + +func TestConfig_LoadNonexistentFile(t *testing.T) { + tempDir := t.TempDir() + tempFile := filepath.Join(tempDir, "nonexistent.yaml") + + // Test Load with nonexistent file + cfg, err := LoadFromPath(tempFile) + if err != nil { + t.Fatalf("Load should not error on nonexistent file: %v", err) + } + + // Should return empty config + if cfg == nil { + t.Fatal("Config should not be nil") + } + + if cfg.Hosts == nil { + t.Fatal("Hosts map should be initialized") + } + + if len(cfg.Hosts) != 0 { + t.Errorf("Expected empty hosts map, got %d entries", len(cfg.Hosts)) + } +} + +func TestConfig_LoadInvalidYAML(t *testing.T) { + tempDir := t.TempDir() + tempFile := filepath.Join(tempDir, "invalid.yaml") + + // Write invalid YAML + err := os.WriteFile(tempFile, []byte("invalid: yaml: content: [[["), 0600) + if err != nil { + t.Fatalf("Failed to write invalid YAML: %v", err) + } + + // Test Load with invalid YAML + _, err = LoadFromPath(tempFile) + if err == nil { + t.Error("Expected error when loading invalid YAML") + } +} + +func TestConfig_SaveCreatesDirectory(t *testing.T) { + tempDir := t.TempDir() + tempFile := filepath.Join(tempDir, "subdir", "config.yaml") + + cfg := &Config{ + Hosts: map[string]HostConfig{ + "test.org": { + Hostname: "test.org", + Token: "token", + }, + }, + } + + // Save should create the directory + err := cfg.SaveToPath(tempFile) + if err != nil { + t.Fatalf("Failed to save config: %v", err) + } + + // Verify directory was created + subdir := filepath.Dir(tempFile) + if _, err := os.Stat(subdir); os.IsNotExist(err) { + t.Error("Save() should have created the directory") + } + + // Verify file exists + if _, err := os.Stat(tempFile); os.IsNotExist(err) { + t.Error("Config file was not created") + } +}