diff --git a/cargo.go b/cargo.go index 68faffc..8935969 100644 --- a/cargo.go +++ b/cargo.go @@ -1,9 +1,5 @@ package main -import ( - "os/exec" -) - type CargoManager struct{} func (c *CargoManager) Install(packages []string) error { @@ -22,19 +18,19 @@ func (c *CargoManager) Name() string { } func (c *CargoManager) InstallManager() error { - if _, err := exec.LookPath("brew"); err != nil { + if _, err := execLookPath("brew"); err != nil { installHomebrew() } - if _, err := exec.LookPath("cargo"); err == nil { + if _, err := execLookPath("cargo"); err == nil { return nil } - cmd := exec.Command("brew", "install", "rust") + cmd := execCommand("brew", "install", "rust") return cmd.Run() } func (c *CargoManager) InstallPackage(pkg string) error { - cmd := exec.Command("cargo", "install", pkg) + cmd := execCommand("cargo", "install", pkg) return cmd.Run() } diff --git a/cargo_test.go b/cargo_test.go new file mode 100644 index 0000000..5129f56 --- /dev/null +++ b/cargo_test.go @@ -0,0 +1,45 @@ +// cargo_test.go +package main + +import ( + "os/exec" + "testing" +) + +func TestCargoManager_Name(t *testing.T) { + cm := &CargoManager{} + if name := cm.Name(); name != "Cargo" { + t.Errorf("Expected name to be 'Cargo', got %s", name) + } +} + +func TestCargoManager_InstallManager(t *testing.T) { + cm := &CargoManager{} + + // Mock exec.LookPath + execLookPath = func(file string) (string, error) { + if file == "cargo" { + return "/usr/bin/cargo", nil + } + return "", exec.ErrNotFound + } + defer func() { execLookPath = exec.LookPath }() + + if err := cm.InstallManager(); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} + +func TestCargoManager_InstallPackage(t *testing.T) { + cm := &CargoManager{} + + // Mock exec.Command + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command("echo", "mocked cargo install") + } + defer func() { execCommand = exec.Command }() + + if err := cm.InstallPackage("test-package"); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} diff --git a/dotfiles.go b/dotfiles.go index 08f3d52..849da76 100644 --- a/dotfiles.go +++ b/dotfiles.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "os/exec" "path/filepath" ) @@ -14,18 +13,17 @@ type DotfilesConfig struct { } func setupDotfiles(config DotfilesConfig) error { - if _, err := exec.LookPath("git"); err != nil { + if _, err := execLookPath("git"); err != nil { return fmt.Errorf("git ist nicht installiert") } - if _, err := exec.LookPath("stow"); err != nil { + if _, err := execLookPath("stow"); err != nil { return fmt.Errorf("gnu stow ist nicht installiert") } dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles") - // cmd := exec.Command("git", "clone", config.GitRepo) - cmd := exec.Command("git", "clone", config.GitRepo, dotfilesDir) + cmd := execCommand("git", "clone", config.GitRepo, dotfilesDir) if err := cmd.Run(); err != nil { return fmt.Errorf("fehler beim Klonen der Dotfiles: %v", err) } @@ -34,7 +32,7 @@ func setupDotfiles(config DotfilesConfig) error { return fmt.Errorf("fehler beim Wechseln in das Dotfiles-Verzeichnis: %v", err) } - cmd = exec.Command("stow", ".", "--override='*'") + cmd = execCommand("stow", ".", "--override='*'") if err := cmd.Run(); err != nil { log.Printf("Fehler beim Linken: %v", err) } diff --git a/flatpak.go b/flatpak.go index 5e8d1a5..4f2bf4c 100644 --- a/flatpak.go +++ b/flatpak.go @@ -75,7 +75,7 @@ func installFlatpak(os *OS, sudoPassword string) error { func addFlatpakRemotes(remotes []Remote) error { for _, remote := range remotes { - cmd := exec.Command("flatpak", "remote-add", "--if-not-exists", remote.Name, remote.URL) + cmd := execCommand("flatpak", "remote-add", "--if-not-exists", remote.Name, remote.URL) if err := cmd.Run(); err != nil { return fmt.Errorf("fehler beim Hinzufügen des Remotes %s: %v", remote.Name, err) } @@ -84,6 +84,6 @@ func addFlatpakRemotes(remotes []Remote) error { } func (f *FlatpakManager) InstallPackage(pkg string) error { - cmd := exec.Command("flatpak", "install", "-y", pkg) + cmd := execCommand("flatpak", "install", "-y", pkg) return cmd.Run() } diff --git a/flatpak_test.go b/flatpak_test.go new file mode 100644 index 0000000..c99e2d5 --- /dev/null +++ b/flatpak_test.go @@ -0,0 +1,44 @@ +// flatpak_test.go +package main + +import ( + "os/exec" + "testing" +) + +func TestFlatpakManager_Name(t *testing.T) { + fm := &FlatpakManager{} + if name := fm.Name(); name != "Flatpak" { + t.Errorf("Expected name to be 'Flatpak', got %s", name) + } +} + +func TestFlatpakManager_InstallManager(t *testing.T) { + fm := &FlatpakManager{ + OS: &OS{PackageManager: "apt"}, + SudoPassword: "testpass", + Config: FlatpakConfig{ + Remotes: []Remote{{Name: "test", URL: "http://test.com"}}, + }, + } + + // Mock exec.LookPath and other functions as needed + + if err := fm.InstallManager(); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} + +func TestFlatpakManager_InstallPackage(t *testing.T) { + fm := &FlatpakManager{} + + // Mock exec.Command + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command("echo", "mocked flatpak install") + } + defer func() { execCommand = exec.Command }() + + if err := fm.InstallPackage("test-package"); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} diff --git a/go.mod b/go.mod index 29cf3f7..b11c96d 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/charmbracelet/x/ansi v0.4.5 // indirect github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -41,6 +42,7 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -49,6 +51,8 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/piglatin v0.0.0-20140311054444-ab61287b9936 // indirect + github.com/stretchr/testify v1.10.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/atomic v1.9.0 // indirect diff --git a/go.sum b/go.sum index afddadc..59f7dbe 100644 --- a/go.sum +++ b/go.sum @@ -118,12 +118,16 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/piglatin v0.0.0-20140311054444-ab61287b9936 h1:QcF4JZjvg9uNP9SdKFXspe6keOBZ1XmXkb25badRIkY= +github.com/stretchr/piglatin v0.0.0-20140311054444-ab61287b9936/go.mod h1:fnVlYnscMLDEmGbdH+GXr7JHxZCj7pCoRap6A74K5lY= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= diff --git a/golang.go b/golang.go index 1bcaca8..b209eab 100644 --- a/golang.go +++ b/golang.go @@ -1,9 +1,5 @@ package main -import ( - "os/exec" -) - type GolangManager struct{} func (g *GolangManager) Install(packages []string) error { @@ -22,19 +18,19 @@ func (g *GolangManager) Name() string { } func (g *GolangManager) InstallManager() error { - if _, err := exec.LookPath("brew"); err != nil { + if _, err := execLookPath("brew"); err != nil { installHomebrew() } - if _, err := exec.LookPath("go"); err == nil { + if _, err := execLookPath("go"); err == nil { return nil } - cmd := exec.Command("brew", "install", "golang") + cmd := execCommand("brew", "install", "golang") return cmd.Run() } func (g *GolangManager) InstallPackage(pkg string) error { - cmd := exec.Command("go", "install", pkg+"@latest") + cmd := execCommand("go", "install", pkg+"@latest") return cmd.Run() } diff --git a/golang_test.go b/golang_test.go new file mode 100644 index 0000000..5e67b0a --- /dev/null +++ b/golang_test.go @@ -0,0 +1,45 @@ +// golang_test.go +package main + +import ( + "os/exec" + "testing" +) + +func TestGolangManager_Name(t *testing.T) { + gm := &GolangManager{} + if name := gm.Name(); name != "Golang" { + t.Errorf("Expected name to be 'Golang', got %s", name) + } +} + +func TestGolangManager_InstallManager(t *testing.T) { + gm := &GolangManager{} + + // Mock exec.LookPath + execLookPath = func(file string) (string, error) { + if file == "go" { + return "/usr/local/go/bin/go", nil + } + return "", exec.ErrNotFound + } + defer func() { execLookPath = exec.LookPath }() + + if err := gm.InstallManager(); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} + +func TestGolangManager_InstallPackage(t *testing.T) { + gm := &GolangManager{} + + // Mock exec.Command + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command("echo", "mocked go install") + } + defer func() { execCommand = exec.Command }() + + if err := gm.InstallPackage("github.com/test/package"); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} diff --git a/homebrew.go b/homebrew.go index 56b7e56..528631f 100644 --- a/homebrew.go +++ b/homebrew.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "os/exec" ) type HomebrewManager struct{} @@ -23,7 +22,7 @@ func (h *HomebrewManager) Name() string { } func (h *HomebrewManager) InstallManager() error { - if _, err := exec.LookPath("brew"); err == nil { + if _, err := execLookPath("brew"); err == nil { return nil } @@ -39,6 +38,6 @@ func installHomebrew() error { } func (h *HomebrewManager) InstallPackage(pkg string) error { - cmd := exec.Command("brew", "install", pkg) + cmd := execCommand("brew", "install", pkg) return cmd.Run() } diff --git a/homebrew_test.go b/homebrew_test.go new file mode 100644 index 0000000..72da6ee --- /dev/null +++ b/homebrew_test.go @@ -0,0 +1,45 @@ +// homebrew_test.go +package main + +import ( + "os/exec" + "testing" +) + +func TestHomebrewManager_Name(t *testing.T) { + hm := &HomebrewManager{} + if name := hm.Name(); name != "Homebrew" { + t.Errorf("Expected name to be 'Homebrew', got %s", name) + } +} + +func TestHomebrewManager_InstallManager(t *testing.T) { + hm := &HomebrewManager{} + + // Mock exec.LookPath and executeShellCommand + execLookPath = func(file string) (string, error) { + if file == "brew" { + return "/usr/local/bin/brew", nil + } + return "", exec.ErrNotFound + } + defer func() { execLookPath = exec.LookPath }() + + if err := hm.InstallManager(); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} + +func TestHomebrewManager_InstallPackage(t *testing.T) { + hm := &HomebrewManager{} + + // Mock exec.Command + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command("echo", "mocked brew install") + } + defer func() { execCommand = exec.Command }() + + if err := hm.InstallPackage("test-package"); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} diff --git a/magefile.go b/magefile.go index 35fe78a..3603577 100644 --- a/magefile.go +++ b/magefile.go @@ -19,7 +19,7 @@ import ( func Build() error { mg.Deps(InstallDeps) fmt.Println("Building...") - cmd := exec.Command("go", "build", "-o", "MyApp", ".") + cmd := exec.Command("go", "build", "-o", "system_setup_tool", ".") return cmd.Run() } @@ -27,7 +27,7 @@ func Build() error { func Install() error { mg.Deps(Build) fmt.Println("Installing...") - return os.Rename("./MyApp", "/usr/bin/MyApp") + return os.Rename("./system_setup_tool", "/usr/bin/system_setup_tool") } // Manage your deps, or running package managers. @@ -56,3 +56,10 @@ func Lint() error { cmd := exec.Command("golangci-lint", "./...") return cmd.Run() } + +// perform all modul tests +func Test() error { + fmt.Println("Testing...") + cmd := exec.Command("go", "test", "./...") + return cmd.Run() +} diff --git a/model.go b/model.go index 0b14fca..41cb2e6 100644 --- a/model.go +++ b/model.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "os/exec" "path/filepath" "strings" @@ -27,7 +26,7 @@ type model struct { } func (m model) installSpecialSoftware() error { - if _, err := exec.LookPath("oh-my-posh"); err == nil { + if _, err := execLookPath("oh-my-posh"); err == nil { fmt.Println("Oh-my-posh ist bereits installiert") } else { poshCommand := "curl -s https://ohmyposh.dev/install.sh | bash -s" diff --git a/osinfo.go b/osinfo.go index 079c938..195dc4c 100644 --- a/osinfo.go +++ b/osinfo.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "os/exec" "strings" tea "github.com/charmbracelet/bubbletea" @@ -120,7 +119,7 @@ func (os *OS) getPackageManager() error { "pacman", } for _, pmname := range pmcommands { - _, err := exec.LookPath(pmname) + _, err := execLookPath(pmname) if err == nil { os.PackageManager = pmname return nil diff --git a/osinfo_test.go b/osinfo_test.go new file mode 100644 index 0000000..ddca2ec --- /dev/null +++ b/osinfo_test.go @@ -0,0 +1,50 @@ +// osmanager_test.go +package main + +import ( + "testing" +) + +func TestNewOSManager(t *testing.T) { + os := &OS{ID: "ubuntu", PackageManager: "apt"} + sudoPassword := "testpassword" + packages := []string{"git", "curl"} + + manager := NewOSManager(os, sudoPassword, packages) + + if manager.OS != os { + t.Errorf("Expected OS to be %v, got %v", os, manager.OS) + } + if manager.SudoPassword != sudoPassword { + t.Errorf("Expected SudoPassword to be %s, got %s", sudoPassword, manager.SudoPassword) + } + if len(manager.Packages) != len(packages) { + t.Errorf("Expected Packages length to be %d, got %d", len(packages), len(manager.Packages)) + } +} + +func TestOSManagerName(t *testing.T) { + manager := &OSManager{} + if manager.Name() != "OS Package Manager" { + t.Errorf("Expected name to be 'OS Package Manager', got %s", manager.Name()) + } +} + +func TestParseOsRelease(t *testing.T) { + osReleaseContent := ` +ID=ubuntu +NAME="Ubuntu" +VERSION_ID="20.04" +` + os := parseOsRelease(osReleaseContent) + + if os.ID != "ubuntu" { + t.Errorf("Expected ID to be 'ubuntu', got %s", os.ID) + } + if os.Name != "Ubuntu" { + t.Errorf("Expected Name to be 'Ubuntu', got %s", os.Name) + } + if os.Version != "20.04" { + t.Errorf("Expected Version to be '20.04', got %s", os.Version) + } +} diff --git a/package.go b/package.go index 32d901a..77b7a46 100644 --- a/package.go +++ b/package.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "os/exec" "strings" ) @@ -13,7 +12,7 @@ type Packages struct { func installPackage(cmd, pkg, sudoPassword string) error { fullCmd := fmt.Sprintf("%s %s", cmd, pkg) - command := exec.Command("sudo", "-S", "sh", "-c", fullCmd) + command := execCommand("sudo", "-S", "sh", "-c", fullCmd) command.Stdin = strings.NewReader(sudoPassword + "\n") output, err := command.CombinedOutput() if err != nil { diff --git a/pipx.go b/pipx.go index 7ba895c..ddbcd34 100644 --- a/pipx.go +++ b/pipx.go @@ -1,9 +1,5 @@ package main -import ( - "os/exec" -) - type PipxManager struct{} func (p *PipxManager) Install(packages []string) error { @@ -23,19 +19,19 @@ func (p *PipxManager) Name() string { } func (p *PipxManager) InstallManager() error { - if _, err := exec.LookPath("brew"); err != nil { + if _, err := execLookPath("brew"); err != nil { installHomebrew() } - if _, err := exec.LookPath("pipx"); err == nil { + if _, err := execLookPath("pipx"); err == nil { return nil } - cmd := exec.Command("brew", "install", "pipx") + cmd := execCommand("brew", "install", "pipx") return cmd.Run() } func (p *PipxManager) InstallPackage(pkg string) error { - cmd := exec.Command("pipx", "install", pkg) + cmd := execCommand("pipx", "install", pkg) return cmd.Run() } diff --git a/pipx_test.go b/pipx_test.go new file mode 100644 index 0000000..a7f7389 --- /dev/null +++ b/pipx_test.go @@ -0,0 +1,45 @@ +// pipx_test.go +package main + +import ( + "os/exec" + "testing" +) + +func TestPipxManager_Name(t *testing.T) { + pm := &PipxManager{} + if name := pm.Name(); name != "Pipx" { + t.Errorf("Expected name to be 'Pipx', got %s", name) + } +} + +func TestPipxManager_InstallManager(t *testing.T) { + pm := &PipxManager{} + + // Mock exec.LookPath + execLookPath = func(file string) (string, error) { + if file == "pipx" { + return "/usr/bin/pipx", nil + } + return "", exec.ErrNotFound + } + defer func() { execLookPath = exec.LookPath }() + + if err := pm.InstallManager(); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} + +func TestPipxManager_InstallPackage(t *testing.T) { + pm := &PipxManager{} + + // Mock exec.Command + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command("echo", "mocked pipx install") + } + defer func() { execCommand = exec.Command }() + + if err := pm.InstallPackage("test-package"); err != nil { + t.Errorf("Expected no error, got %v", err) + } +} diff --git a/tui.go b/tui.go index cc4ee26..ab1be10 100644 --- a/tui.go +++ b/tui.go @@ -18,8 +18,6 @@ var ( unavailablePackages []string ) -// type installedItemMsg string - type installedPkgMsg string func run(cmd *cobra.Command, args []string) { diff --git a/utils.go b/utils.go index ea0de75..58f6896 100644 --- a/utils.go +++ b/utils.go @@ -2,17 +2,19 @@ package main import ( "fmt" - // "io" "log" - // "net/http" "os" "os/exec" - // "runtime" "github.com/charmbracelet/huh" "github.com/schollz/progressbar/v3" ) +var ( + execCommand = exec.Command + execLookPath = exec.LookPath +) + func getSudoPassword() (string, error) { var password string form := huh.NewForm( @@ -31,37 +33,6 @@ func getSudoPassword() (string, error) { return password, nil } -// func downloadGolang(golangVersion string) error { -// var link string -// if runtime.GOARCH == "arm64" { -// link = "https://go.dev/dl/go" + golangVersion + ".linux-arm64.tar.gz" -// } else { -// link = "https://go.dev/dl/go" + golangVersion + ".linux-amd64.tar.gz" -// } -// resp, err := http.Get(link) -// if err != nil { -// return fmt.Errorf("fehler beim Herunterladen von Go: %v", err) -// } -// defer resp.Body.Close() - -// if resp.StatusCode != http.StatusOK { -// return fmt.Errorf("unerwarteter HTTP-Status: %s", resp.Status) -// } - -// outFile, err := os.Create("go" + golangVersion + ".linux-" + runtime.GOARCH + ".tar.gz") -// if err != nil { -// return fmt.Errorf("fehler beim Erstellen der Ausgabedatei: %v", err) -// } -// defer outFile.Close() - -// _, err = io.Copy(outFile, resp.Body) -// if err != nil { -// return fmt.Errorf("fehler beim Schreiben der Ausgabedatei: %v", err) -// } - -// return nil -// } - func max(a, b int) int { if a > b { return a @@ -69,18 +40,8 @@ func max(a, b int) int { return b } -// func installPackageWithProgress(name string, installFunc func() error) error { -// err := installFunc() -// if err != nil { -// fmt.Printf("\r❌ %s\n", name) -// return err -// } -// fmt.Printf("\r✓ %s\n", name) -// return nil -// } - func executeShellCommand(command string, env string) error { - cmd := exec.Command("bash", "-c", command) + cmd := execCommand("bash", "-c", command) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, env) output, err := cmd.CombinedOutput() diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 0000000..20dcde6 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,78 @@ +package main + +import ( + "os/exec" + "testing" +) + +func TestMax(t *testing.T) { + tests := []struct { + a, b, want int + }{ + {1, 2, 2}, + {5, 3, 5}, + {0, 0, 0}, + {-1, -5, -1}, + } + + for _, tt := range tests { + got := max(tt.a, tt.b) + if got != tt.want { + t.Errorf("max(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want) + } + } +} + +func TestExecuteShellCommand(t *testing.T) { + // Mock execCommand + oldExecCommand := execCommand + defer func() { execCommand = oldExecCommand }() + + execCommand = func(command string, args ...string) *exec.Cmd { + return exec.Command("echo", "mocked command") + } + + err := executeShellCommand("test command", "TEST_ENV=value") + if err != nil { + t.Errorf("executeShellCommand() error = %v; want nil", err) + } +} + +func TestInstallWithProgress(t *testing.T) { + mockManager := &MockPackageManager{ + packages: []string{"pkg1", "pkg2"}, + } + + err := installWithProgress(mockManager, mockManager.packages) + if err != nil { + t.Errorf("installWithProgress() error = %v; want nil", err) + } + + if len(mockManager.installedPackages) != len(mockManager.packages) { + t.Errorf("installWithProgress() installed %d packages; want %d", len(mockManager.installedPackages), len(mockManager.packages)) + } +} + +// MockPackageManager implementiert das PackageManager Interface für Tests +type MockPackageManager struct { + packages []string + installedPackages []string +} + +func (m *MockPackageManager) Install(packages []string) error { + m.installedPackages = append(m.installedPackages, packages...) + return nil +} + +func (m *MockPackageManager) InstallPackage(pkg string) error { + m.installedPackages = append(m.installedPackages, pkg) + return nil +} + +func (m *MockPackageManager) InstallManager() error { + return nil +} + +func (m *MockPackageManager) Name() string { + return "MockManager" +}