From 73e4452b7caca9d0fe67e9faea4954a104deb066 Mon Sep 17 00:00:00 2001 From: spezifisch Date: Sun, 13 Oct 2024 18:04:27 +0200 Subject: [PATCH] [main/test] fix tests, reorder main so that it's more testable --- stmps.go | 107 +++++++++++++++++++++++++++++++------------------- stmps_test.go | 16 ++++++-- 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/stmps.go b/stmps.go index e1399fd..7586604 100644 --- a/stmps.go +++ b/stmps.go @@ -22,26 +22,36 @@ import ( var osExit = os.Exit // A variable to allow mocking os.Exit in tests var headlessMode bool // This can be set to true during tests +var testMode bool // This can be set to true during tests, too -func readConfig() { +func readConfig(configFile *string) error { required_properties := []string{"auth.username", "auth.password", "server.host"} - viper.SetConfigName("stmp") - viper.SetConfigType("toml") - viper.AddConfigPath("$HOME/.config/stmp") - viper.AddConfigPath(".") - err := viper.ReadInConfig() + if configFile != nil { + // use custom config file + viper.SetConfigFile(*configFile) + } else { + // lookup default dirs + viper.SetConfigName("stmp") // TODO this should be stmps + viper.SetConfigType("toml") + viper.AddConfigPath("$HOME/.config/stmp") // TODO this should be stmps + viper.AddConfigPath(".") + } + // read it + err := viper.ReadInConfig() if err != nil { - fmt.Printf("Config file error: %s \n", err) - osExit(1) + return fmt.Errorf("Config file error: %s\n", err) } + // validate for _, prop := range required_properties { if !viper.IsSet(prop) { - fmt.Printf("Config property %s is required\n", prop) + return fmt.Errorf("Config property %s is required\n", prop) } } + + return nil } // parseConfig takes the first non-flag arguments from flags and parses it @@ -85,11 +95,13 @@ func initCommandHandler(logger *logger.Logger) { } func main() { + // parse flags and config help := flag.Bool("help", false, "Print usage") enableMpris := flag.Bool("mpris", false, "Enable MPRIS2") list := flag.Bool("list", false, "list server data") cpuprofile := flag.String("cpuprofile", "", "write cpu profile to `file`") memprofile := flag.String("memprofile", "", "write memory profile to `file`") + configFile := flag.String("config", "c", "use config `file`") flag.Parse() if *help { @@ -111,15 +123,58 @@ func main() { defer pprof.StopCPUProfile() } + // config gathering if len(flag.Args()) > 0 { parseConfig() - } else { - readConfig() + } + + if err := readConfig(configFile); err != nil { + if configFile == nil { + fmt.Fprintf(os.Stderr, "Failed to read configuration: configuration file is nil\n") + } else { + fmt.Fprintf(os.Stderr, "Failed to read configuration from file '%s': %v\n", *configFile, err) + } + osExit(1) } logger := logger.Init() initCommandHandler(logger) + // init mpv engine + player, err := mpvplayer.NewPlayer(logger) + if err != nil { + fmt.Println("Unable to initialize mpv. Is mpv installed?") + osExit(1) + } + + var mprisPlayer *remote.MprisPlayer + // init mpris2 player control (linux only but fails gracefully on other systems) + if *enableMpris { + mprisPlayer, err = remote.RegisterMprisPlayer(player, logger) + if err != nil { + fmt.Printf("Unable to register MPRIS with DBUS: %s\n", err) + fmt.Println("Try running without MPRIS") + osExit(1) + } + defer mprisPlayer.Close() + } + + // init macos mediaplayer control + if runtime.GOOS == "darwin" { + if err = remote.RegisterMPMediaHandler(player, logger); err != nil { + fmt.Printf("Unable to initialize MediaPlayer bindings: %s\n", err) + osExit(1) + } else { + logger.Print("MacOS MediaPlayer registered") + } + } + + if testMode { + fmt.Println("Running in test mode for testing.") + osExit(0) + return + } + connection := subsonic.Init(logger) connection.SetClientInfo(clientName, clientVersion) connection.Username = viper.GetString("auth.username") @@ -171,37 +226,9 @@ func main() { osExit(0) } - // init mpv engine - player, err := mpvplayer.NewPlayer(logger) - if err != nil { - fmt.Println("Unable to initialize mpv. Is mpv installed?") - osExit(1) - } - - var mprisPlayer *remote.MprisPlayer - // init mpris2 player control (linux only but fails gracefully on other systems) - if *enableMpris { - mprisPlayer, err = remote.RegisterMprisPlayer(player, logger) - if err != nil { - fmt.Printf("Unable to register MPRIS with DBUS: %s\n", err) - fmt.Println("Try running without MPRIS") - osExit(1) - } - defer mprisPlayer.Close() - } - - // init macos mediaplayer control - if runtime.GOOS == "darwin" { - if err = remote.RegisterMPMediaHandler(player, logger); err != nil { - fmt.Printf("Unable to initialize MediaPlayer bindings: %s\n", err) - osExit(1) - } else { - logger.Print("MacOS MediaPlayer registered") - } - } - if headlessMode { fmt.Println("Running in headless mode for testing.") + osExit(0) return } diff --git a/stmps_test.go b/stmps_test.go index a7fa512..a889e63 100644 --- a/stmps_test.go +++ b/stmps_test.go @@ -2,6 +2,7 @@ package main import ( "os" + "runtime" "testing" "github.com/spezifisch/stmps/logger" @@ -22,21 +23,30 @@ func TestMainWithoutTUI(t *testing.T) { exitCalled := false osExit = func(code int) { exitCalled = true + if code != 0 { - t.Fatalf("Unexpected exit with code: %d", code) + // Capture and print the stack trace + stackBuf := make([]byte, 1024) + stackSize := runtime.Stack(stackBuf, false) + stackTrace := string(stackBuf[:stackSize]) + + // Print the stack trace with new lines only + t.Fatalf("Unexpected exit with code: %d\nStack trace:\n%s\n", code, stackTrace) } // Since we don't abort execution here, we will run main() until the end or a panic. } headlessMode = true + testMode = true - // Restore osExit after the test + // Restore patches after the test defer func() { osExit = os.Exit headlessMode = false + testMode = false }() // Set command-line arguments to trigger the help flag - os.Args = []string{"cmd", "--help"} + os.Args = []string{"cmd", "--config=stmp-example.toml", "--help"} main()