diff --git a/Makefile b/Makefile index 918e459..748c480 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,7 @@ build: .PHONY: run run: ./sofmani + +.PHONY: test +test: + go test -v ./... diff --git a/appconfig/appconfig.go b/appconfig/appconfig.go index 9b7d7ca..2906748 100644 --- a/appconfig/appconfig.go +++ b/appconfig/appconfig.go @@ -1,10 +1,13 @@ package appconfig import ( + "errors" "fmt" + "io/fs" "os" "path/filepath" "runtime" + "strings" "github.com/eschao/config" ) @@ -139,8 +142,7 @@ func ContainsPlatform(platforms *[]Platform, platform Platform) bool { return false } -func ParseConfig(version string) (*AppConfig, error) { - overrides := ParseCliConfig(version) +func ParseConfig(version string, overrides *AppCliConfig) (*AppConfig, error) { file := overrides.ConfigFile ext := filepath.Ext(file) switch ext { @@ -157,7 +159,7 @@ func ParseConfig(version string) (*AppConfig, error) { } return appConfig, nil } - return nil, fmt.Errorf("Unsupported config file extension %s", ext) + return nil, fmt.Errorf("Unsupported config file extension %s (filename: %s)", ext, file) } func ParseConfigFrom(file string) (*AppConfig, error) { @@ -228,7 +230,14 @@ func ParseCliConfig(version string) *AppCliConfig { fmt.Println(version) os.Exit(0) default: - file = args[0] + if strings.HasPrefix(strings.TrimSpace(args[0]), "-test.") { + break + } + _, err := os.Stat(file) + exists := !errors.Is(err, fs.ErrNotExist) + if exists { + file = args[0] + } } args = args[1:] } diff --git a/appconfig/appconfig_test.go b/appconfig/appconfig_test.go new file mode 100644 index 0000000..a361112 --- /dev/null +++ b/appconfig/appconfig_test.go @@ -0,0 +1,91 @@ +package appconfig + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPlatformMapResolve(t *testing.T) { + tests := []struct { + name string + platform string + expected *string + }{ + {"MacOS", "darwin", strPtr("macos")}, + {"Linux", "linux", strPtr("linux")}, + {"Windows", "windows", strPtr("windows")}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if runtime.GOOS != tt.platform { + t.Skipf("Skipping test on %s", runtime.GOOS) + } + pm := PlatformMap[string]{ + MacOS: strPtr("macos"), + Linux: strPtr("linux"), + Windows: strPtr("windows"), + } + assert.Equal(t, tt.expected, pm.Resolve()) + }) + } +} + +func TestAppConfigEnviron(t *testing.T) { + env := map[string]string{"KEY1": "value1", "KEY2": "value2"} + config := AppConfig{Env: &env} + expected := []string{"KEY1=value1", "KEY2=value2"} + assert.ElementsMatch(t, expected, config.Environ()) +} + +func TestInstallerEnviron(t *testing.T) { + env := map[string]string{"KEY1": "value1", "KEY2": "value2"} + installer := Installer{Env: &env} + expected := []string{"KEY1=value1", "KEY2=value2"} + assert.ElementsMatch(t, expected, installer.Environ()) +} + +func TestContainsPlatform(t *testing.T) { + platforms := []Platform{PlatformMacos, PlatformLinux} + assert.True(t, ContainsPlatform(&platforms, PlatformMacos)) + assert.False(t, ContainsPlatform(&platforms, PlatformWindows)) +} + +func TestParseConfig(t *testing.T) { + // Create a temporary config file + file, err := os.CreateTemp("", "config.*.json") + assert.NoError(t, err) + defer os.Remove(file.Name()) + + _, err = file.WriteString(`{"debug": true, "check_updates": false}`) + assert.NoError(t, err) + file.Close() + + // Test parsing the config file + overrides := AppCliConfig{ConfigFile: file.Name()} + config, err := ParseConfig("1.0.0", &overrides) + assert.NoError(t, err) + assert.True(t, config.Debug) + assert.False(t, config.CheckUpdates) +} + +func TestFindConfigFile(t *testing.T) { + // Create a temporary config file + dir := t.TempDir() + file := filepath.Join(dir, "sofmani.json") + err := os.WriteFile(file, []byte(`{"debug": true}`), 0644) + assert.NoError(t, err) + + // Test finding the config file + os.Chdir(dir) + assert.True(t, strings.HasSuffix(FindConfigFile(), file)) +} + +func strPtr(s string) *string { + return &s +} diff --git a/config.go b/config.go index 18d463b..19f8107 100644 --- a/config.go +++ b/config.go @@ -5,7 +5,8 @@ import ( ) func LoadConfig(version string) (*appconfig.AppConfig, error) { - cfg, err := appconfig.ParseConfig(version) + overrides := appconfig.ParseCliConfig(version) + cfg, err := appconfig.ParseConfig(version, overrides) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index b1cd947..cbef31f 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,14 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/eschao/config v0.1.0 github.com/fatih/color v1.18.0 + github.com/stretchr/testify v1.9.0 ) require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/stretchr/testify v1.9.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.25.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/installer/installer_test.go b/installer/installer_test.go new file mode 100644 index 0000000..8b54915 --- /dev/null +++ b/installer/installer_test.go @@ -0,0 +1,91 @@ +package installer + +import ( + "testing" + + "github.com/chenasraf/sofmani/appconfig" + "github.com/chenasraf/sofmani/logger" + "github.com/stretchr/testify/assert" +) + +type MockInstaller struct { + info *appconfig.Installer + isInstalled bool + needsUpdate bool + installError error + updateError error + checkInstall error + checkUpdate error +} + +func (m *MockInstaller) GetInfo() *appconfig.Installer { + return m.info +} + +func (m *MockInstaller) CheckIsInstalled() (error, bool) { + return m.checkInstall, m.isInstalled +} + +func (m *MockInstaller) CheckNeedsUpdate() (error, bool) { + return m.checkUpdate, m.needsUpdate +} + +func (m *MockInstaller) Install() error { + return m.installError +} + +func (m *MockInstaller) Update() error { + return m.updateError +} + +func TestGetInstaller(t *testing.T) { + config := &appconfig.AppConfig{} + logger.InitLogger(config) + installer := &appconfig.Installer{Type: appconfig.InstallerTypeBrew} + err, inst := GetInstaller(config, installer) + assert.NoError(t, err) + assert.NotNil(t, inst) +} + +func TestInstallerWithDefaults(t *testing.T) { + opts := map[string]any{"key": "value"} + defaults := &appconfig.AppConfigDefaults{ + Type: &map[appconfig.InstallerType]appconfig.Installer{ + appconfig.InstallerTypeBrew: {Opts: &opts}, + }, + } + installer := &appconfig.Installer{Type: appconfig.InstallerTypeBrew, Opts: &map[string]any{}} + result := InstallerWithDefaults(installer, appconfig.InstallerTypeBrew, defaults) + assert.Equal(t, "value", (*result.Opts)["key"]) +} + +func TestGetCurrentPlatform(t *testing.T) { + platform := GetCurrentPlatform() + assert.Contains(t, []appconfig.Platform{appconfig.PlatformMacos, appconfig.PlatformLinux, appconfig.PlatformWindows}, platform) +} + +func TestRunInstaller(t *testing.T) { + config := &appconfig.AppConfig{} + mockInstaller := &MockInstaller{ + info: &appconfig.Installer{Name: strPtr("test"), Type: appconfig.InstallerTypeBrew}, + isInstalled: false, + } + err := RunInstaller(config, mockInstaller) + assert.NoError(t, err) +} + +func TestGetShouldRunOnOS(t *testing.T) { + installer := &MockInstaller{ + info: &appconfig.Installer{ + Platforms: &appconfig.Platforms{ + Only: &[]appconfig.Platform{appconfig.PlatformMacos}, + }, + }, + } + assert.True(t, GetShouldRunOnOS(installer, appconfig.PlatformMacos)) + assert.False(t, GetShouldRunOnOS(installer, appconfig.PlatformLinux)) +} + +func strPtr(s string) *string { + return &s +} diff --git a/main.go b/main.go index 27ea906..e480226 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( var version []byte func main() { + fmt.Println("Args: ", os.Args) cfg, err := LoadConfig(strings.TrimSpace(string(version))) if err != nil { fmt.Println(fmt.Errorf("Error loading config: %v", err))