package mining import ( "os" "path/filepath" "testing" ) func TestSettingsManager_DefaultSettings_Good(t *testing.T) { defaults := DefaultSettings() if defaults.Window.Width != 1400 { t.Errorf("Expected default width 1400, got %d", defaults.Window.Width) } if defaults.Window.Height != 900 { t.Errorf("Expected default height 900, got %d", defaults.Window.Height) } if defaults.MinerDefaults.CPUMaxThreadsHint != 50 { t.Errorf("Expected default CPU hint 50, got %d", defaults.MinerDefaults.CPUMaxThreadsHint) } if defaults.MinerDefaults.CPUThrottleThreshold != 80 { t.Errorf("Expected default throttle threshold 80, got %d", defaults.MinerDefaults.CPUThrottleThreshold) } if !defaults.PauseOnBattery { t.Error("Expected PauseOnBattery to be true by default") } } func TestSettingsManager_SaveAndLoad_Good(t *testing.T) { tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } sm.settings.Window.Width = 1920 sm.settings.Window.Height = 1080 sm.settings.StartOnBoot = true sm.settings.AutostartMiners = true sm.settings.CPUThrottlePercent = 50 err := sm.Save() if err != nil { t.Fatalf("Failed to save settings: %v", err) } if _, err := os.Stat(settingsPath); os.IsNotExist(err) { t.Fatal("Settings file was not created") } sm2 := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } err = sm2.Load() if err != nil { t.Fatalf("Failed to load settings: %v", err) } if sm2.settings.Window.Width != 1920 { t.Errorf("Expected width 1920, got %d", sm2.settings.Window.Width) } if sm2.settings.Window.Height != 1080 { t.Errorf("Expected height 1080, got %d", sm2.settings.Window.Height) } if !sm2.settings.StartOnBoot { t.Error("Expected StartOnBoot to be true") } if !sm2.settings.AutostartMiners { t.Error("Expected AutostartMiners to be true") } if sm2.settings.CPUThrottlePercent != 50 { t.Errorf("Expected CPUThrottlePercent 50, got %d", sm2.settings.CPUThrottlePercent) } } func TestSettingsManager_SaveAndLoad_Bad(t *testing.T) { // Load from a path that does not exist — must return an error. sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: filepath.Join(t.TempDir(), "does_not_exist", "settings.json"), } if err := sm.Load(); err == nil { t.Error("Expected error loading from missing path, got nil") } } func TestSettingsManager_UpdateWindowState_Good(t *testing.T) { tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } err := sm.UpdateWindowState(100, 200, 800, 600, false) if err != nil { t.Fatalf("Failed to update window state: %v", err) } state := sm.GetWindowState() if state.X != 100 { t.Errorf("Expected X 100, got %d", state.X) } if state.Y != 200 { t.Errorf("Expected Y 200, got %d", state.Y) } if state.Width != 800 { t.Errorf("Expected Width 800, got %d", state.Width) } if state.Height != 600 { t.Errorf("Expected Height 600, got %d", state.Height) } } func TestSettingsManager_SetCPUThrottle_Good(t *testing.T) { tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } err := sm.SetCPUThrottle(true, 30) if err != nil { t.Fatalf("Failed to set CPU throttle: %v", err) } settings := sm.Get() if !settings.EnableCPUThrottle { t.Error("Expected EnableCPUThrottle to be true") } if settings.CPUThrottlePercent != 30 { t.Errorf("Expected CPUThrottlePercent 30, got %d", settings.CPUThrottlePercent) } } func TestSettingsManager_SetCPUThrottle_Bad(t *testing.T) { // An out-of-range percentage (>100) must be ignored, leaving the prior value unchanged. tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } if err := sm.SetCPUThrottle(true, 30); err != nil { t.Fatalf("Setup: failed to set initial throttle: %v", err) } if err := sm.SetCPUThrottle(true, 150); err != nil { t.Fatalf("Expected no error on invalid percent, got: %v", err) } settings := sm.Get() if settings.CPUThrottlePercent != 30 { t.Errorf("Expected CPUThrottlePercent to remain 30 after invalid input, got %d", settings.CPUThrottlePercent) } } func TestSettingsManager_SetMinerDefaults_Good(t *testing.T) { tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } minerDefaults := MinerDefaults{ DefaultPool: "stratum+tcp://pool.example.com:3333", DefaultWallet: "wallet123", DefaultAlgorithm: "rx/0", CPUMaxThreadsHint: 25, CPUThrottleThreshold: 90, } err := sm.SetMinerDefaults(minerDefaults) if err != nil { t.Fatalf("Failed to set miner defaults: %v", err) } settings := sm.Get() if settings.MinerDefaults.DefaultPool != "stratum+tcp://pool.example.com:3333" { t.Errorf("Expected pool to be set, got %s", settings.MinerDefaults.DefaultPool) } if settings.MinerDefaults.CPUMaxThreadsHint != 25 { t.Errorf("Expected CPUMaxThreadsHint 25, got %d", settings.MinerDefaults.CPUMaxThreadsHint) } } func TestSettingsManager_ConcurrentAccess_Ugly(t *testing.T) { // Ugly: concurrent reads and writes must not race or corrupt state. tmpDir := t.TempDir() settingsPath := filepath.Join(tmpDir, "settings.json") sm := &SettingsManager{ settings: DefaultSettings(), settingsPath: settingsPath, } done := make(chan bool) for i := 0; i < 10; i++ { go func(n int) { for j := 0; j < 100; j++ { _ = sm.Get() sm.UpdateWindowState(n*10, n*10, 800+n, 600+n, false) } done <- true }(i) } for i := 0; i < 10; i++ { <-done } state := sm.GetWindowState() if state.Width < 800 || state.Width > 900 { t.Errorf("Unexpected width after concurrent access: %d", state.Width) } }