refactor: implement mocking functions and tests

This commit is contained in:
Patryk Hegenberg 2025-01-15 21:39:17 +01:00
parent 339dba4e13
commit f8ef2ef2d5
21 changed files with 398 additions and 90 deletions

View file

@ -1,9 +1,5 @@
package main package main
import (
"os/exec"
)
type CargoManager struct{} type CargoManager struct{}
func (c *CargoManager) Install(packages []string) error { func (c *CargoManager) Install(packages []string) error {
@ -22,19 +18,19 @@ func (c *CargoManager) Name() string {
} }
func (c *CargoManager) InstallManager() error { func (c *CargoManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil { if _, err := execLookPath("brew"); err != nil {
installHomebrew() installHomebrew()
} }
if _, err := exec.LookPath("cargo"); err == nil { if _, err := execLookPath("cargo"); err == nil {
return nil return nil
} }
cmd := exec.Command("brew", "install", "rust") cmd := execCommand("brew", "install", "rust")
return cmd.Run() return cmd.Run()
} }
func (c *CargoManager) InstallPackage(pkg string) error { func (c *CargoManager) InstallPackage(pkg string) error {
cmd := exec.Command("cargo", "install", pkg) cmd := execCommand("cargo", "install", pkg)
return cmd.Run() return cmd.Run()
} }

45
cargo_test.go Normal file
View file

@ -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)
}
}

View file

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
) )
@ -14,18 +13,17 @@ type DotfilesConfig struct {
} }
func setupDotfiles(config DotfilesConfig) error { 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") 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") return fmt.Errorf("gnu stow ist nicht installiert")
} }
dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles") dotfilesDir := filepath.Join(os.Getenv("HOME"), "dotfiles")
// cmd := exec.Command("git", "clone", config.GitRepo) cmd := execCommand("git", "clone", config.GitRepo, dotfilesDir)
cmd := exec.Command("git", "clone", config.GitRepo, dotfilesDir)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("fehler beim Klonen der Dotfiles: %v", err) 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) 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 { if err := cmd.Run(); err != nil {
log.Printf("Fehler beim Linken: %v", err) log.Printf("Fehler beim Linken: %v", err)
} }

View file

@ -75,7 +75,7 @@ func installFlatpak(os *OS, sudoPassword string) error {
func addFlatpakRemotes(remotes []Remote) error { func addFlatpakRemotes(remotes []Remote) error {
for _, remote := range remotes { 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 { if err := cmd.Run(); err != nil {
return fmt.Errorf("fehler beim Hinzufügen des Remotes %s: %v", remote.Name, err) 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 { func (f *FlatpakManager) InstallPackage(pkg string) error {
cmd := exec.Command("flatpak", "install", "-y", pkg) cmd := execCommand("flatpak", "install", "-y", pkg)
return cmd.Run() return cmd.Run()
} }

44
flatpak_test.go Normal file
View file

@ -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)
}
}

4
go.mod
View file

@ -20,6 +20,7 @@ require (
github.com/charmbracelet/x/ansi v0.4.5 // indirect 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/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
github.com/charmbracelet/x/term v0.2.1 // 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/dustin/go-humanize v1.0.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fsnotify/fsnotify v1.7.0 // 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/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // 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/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.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/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // 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/subosito/gotenv v1.6.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect

4
go.sum
View file

@ -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.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.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.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.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.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.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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 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= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=

View file

@ -1,9 +1,5 @@
package main package main
import (
"os/exec"
)
type GolangManager struct{} type GolangManager struct{}
func (g *GolangManager) Install(packages []string) error { func (g *GolangManager) Install(packages []string) error {
@ -22,19 +18,19 @@ func (g *GolangManager) Name() string {
} }
func (g *GolangManager) InstallManager() error { func (g *GolangManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil { if _, err := execLookPath("brew"); err != nil {
installHomebrew() installHomebrew()
} }
if _, err := exec.LookPath("go"); err == nil { if _, err := execLookPath("go"); err == nil {
return nil return nil
} }
cmd := exec.Command("brew", "install", "golang") cmd := execCommand("brew", "install", "golang")
return cmd.Run() return cmd.Run()
} }
func (g *GolangManager) InstallPackage(pkg string) error { func (g *GolangManager) InstallPackage(pkg string) error {
cmd := exec.Command("go", "install", pkg+"@latest") cmd := execCommand("go", "install", pkg+"@latest")
return cmd.Run() return cmd.Run()
} }

45
golang_test.go Normal file
View file

@ -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)
}
}

View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"os/exec"
) )
type HomebrewManager struct{} type HomebrewManager struct{}
@ -23,7 +22,7 @@ func (h *HomebrewManager) Name() string {
} }
func (h *HomebrewManager) InstallManager() error { func (h *HomebrewManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err == nil { if _, err := execLookPath("brew"); err == nil {
return nil return nil
} }
@ -39,6 +38,6 @@ func installHomebrew() error {
} }
func (h *HomebrewManager) InstallPackage(pkg string) error { func (h *HomebrewManager) InstallPackage(pkg string) error {
cmd := exec.Command("brew", "install", pkg) cmd := execCommand("brew", "install", pkg)
return cmd.Run() return cmd.Run()
} }

45
homebrew_test.go Normal file
View file

@ -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)
}
}

View file

@ -19,7 +19,7 @@ import (
func Build() error { func Build() error {
mg.Deps(InstallDeps) mg.Deps(InstallDeps)
fmt.Println("Building...") fmt.Println("Building...")
cmd := exec.Command("go", "build", "-o", "MyApp", ".") cmd := exec.Command("go", "build", "-o", "system_setup_tool", ".")
return cmd.Run() return cmd.Run()
} }
@ -27,7 +27,7 @@ func Build() error {
func Install() error { func Install() error {
mg.Deps(Build) mg.Deps(Build)
fmt.Println("Installing...") 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. // Manage your deps, or running package managers.
@ -56,3 +56,10 @@ func Lint() error {
cmd := exec.Command("golangci-lint", "./...") cmd := exec.Command("golangci-lint", "./...")
return cmd.Run() return cmd.Run()
} }
// perform all modul tests
func Test() error {
fmt.Println("Testing...")
cmd := exec.Command("go", "test", "./...")
return cmd.Run()
}

View file

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@ -27,7 +26,7 @@ type model struct {
} }
func (m model) installSpecialSoftware() error { 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") fmt.Println("Oh-my-posh ist bereits installiert")
} else { } else {
poshCommand := "curl -s https://ohmyposh.dev/install.sh | bash -s" poshCommand := "curl -s https://ohmyposh.dev/install.sh | bash -s"

View file

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"strings" "strings"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
@ -120,7 +119,7 @@ func (os *OS) getPackageManager() error {
"pacman", "pacman",
} }
for _, pmname := range pmcommands { for _, pmname := range pmcommands {
_, err := exec.LookPath(pmname) _, err := execLookPath(pmname)
if err == nil { if err == nil {
os.PackageManager = pmname os.PackageManager = pmname
return nil return nil

50
osinfo_test.go Normal file
View file

@ -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)
}
}

View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"os/exec"
"strings" "strings"
) )
@ -13,7 +12,7 @@ type Packages struct {
func installPackage(cmd, pkg, sudoPassword string) error { func installPackage(cmd, pkg, sudoPassword string) error {
fullCmd := fmt.Sprintf("%s %s", cmd, pkg) 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") command.Stdin = strings.NewReader(sudoPassword + "\n")
output, err := command.CombinedOutput() output, err := command.CombinedOutput()
if err != nil { if err != nil {

12
pipx.go
View file

@ -1,9 +1,5 @@
package main package main
import (
"os/exec"
)
type PipxManager struct{} type PipxManager struct{}
func (p *PipxManager) Install(packages []string) error { func (p *PipxManager) Install(packages []string) error {
@ -23,19 +19,19 @@ func (p *PipxManager) Name() string {
} }
func (p *PipxManager) InstallManager() error { func (p *PipxManager) InstallManager() error {
if _, err := exec.LookPath("brew"); err != nil { if _, err := execLookPath("brew"); err != nil {
installHomebrew() installHomebrew()
} }
if _, err := exec.LookPath("pipx"); err == nil { if _, err := execLookPath("pipx"); err == nil {
return nil return nil
} }
cmd := exec.Command("brew", "install", "pipx") cmd := execCommand("brew", "install", "pipx")
return cmd.Run() return cmd.Run()
} }
func (p *PipxManager) InstallPackage(pkg string) error { func (p *PipxManager) InstallPackage(pkg string) error {
cmd := exec.Command("pipx", "install", pkg) cmd := execCommand("pipx", "install", pkg)
return cmd.Run() return cmd.Run()
} }

45
pipx_test.go Normal file
View file

@ -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)
}
}

2
tui.go
View file

@ -18,8 +18,6 @@ var (
unavailablePackages []string unavailablePackages []string
) )
// type installedItemMsg string
type installedPkgMsg string type installedPkgMsg string
func run(cmd *cobra.Command, args []string) { func run(cmd *cobra.Command, args []string) {

View file

@ -2,17 +2,19 @@ package main
import ( import (
"fmt" "fmt"
// "io"
"log" "log"
// "net/http"
"os" "os"
"os/exec" "os/exec"
// "runtime"
"github.com/charmbracelet/huh" "github.com/charmbracelet/huh"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
) )
var (
execCommand = exec.Command
execLookPath = exec.LookPath
)
func getSudoPassword() (string, error) { func getSudoPassword() (string, error) {
var password string var password string
form := huh.NewForm( form := huh.NewForm(
@ -31,37 +33,6 @@ func getSudoPassword() (string, error) {
return password, nil 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 { func max(a, b int) int {
if a > b { if a > b {
return a return a
@ -69,18 +40,8 @@ func max(a, b int) int {
return b 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 { func executeShellCommand(command string, env string) error {
cmd := exec.Command("bash", "-c", command) cmd := execCommand("bash", "-c", command)
cmd.Env = os.Environ() cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, env) cmd.Env = append(cmd.Env, env)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()

78
utils_test.go Normal file
View file

@ -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"
}