using System; using System.Collections.Generic; using System.IO; using System.Windows; using Microsoft.Data.Sqlite; using Xunit; using ytLive.Services; using ytLive.ViewModels; namespace ytLive.Tests; /// /// The desktop-"lock" bug (2026-10-10): at launch the main window ACTIVES /// (WPF default ShowActivated = true), and when the creator is already /// playing an exclusive-fullscreen game, activating LlamaCasty makes Windows /// drop that game to the taskbar; the app's 1920×1040 window then sits over the /// whole work area, so the desktop looks locked and the game can't be reached /// with the mouse. Fix: the window opens WITHOUT activating when a full-screen /// game owns the foreground at launch — ShowActivated = !FullscreenGameRunningNow. /// These tests pin that rule using the FullScreenDetectorOverride seam, /// so no real Win32 foreground state is touched. /// [Collection("RealApp")] public sealed class DesktopLockTests { private readonly RealAppHost _app; public DesktopLockTests(RealAppHost app) => _app = app; [Fact] public void MainWindow_Does_Not_Steal_Focus_When_A_Fullscreen_Game_Is_Foreground() { _app.Run(() => { using var _ = new TempLayout(); MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: 0); try { var window = new MainWindow(); try { // The regression: a full-screen game already owns the screen, so // the window must open WITHOUT activating to keep the game live. Assert.False(window.ShowActivated, "launching while a full-screen game owns the foreground must not steal focus"); } finally { window.Close(); } } finally { MainViewModel.FullScreenDetectorOverride = null; } }); } [Fact] public void MainWindow_Normal_Launch_Still_Activates() { _app.Run(() => { using var _ = new TempLayout(); MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: null); try { var window = new MainWindow(); try { // No game running: behaviour is exactly as before the fix. Assert.True(window.ShowActivated, "a normal launch (no full-screen game) must keep the default activate-on-show"); } finally { window.Close(); } } finally { MainViewModel.FullScreenDetectorOverride = null; } }); } [Fact] public void FullscreenGameRunningNow_Reflects_The_Foreground_Monitor() { _app.Run(() => { MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: 0); try { var gameVm = new MainViewModel(); Assert.True(gameVm.FullscreenGameRunningNow); } finally { MainViewModel.FullScreenDetectorOverride = null; } MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: null); try { var idleVm = new MainViewModel(); Assert.False(idleVm.FullscreenGameRunningNow); } finally { MainViewModel.FullScreenDetectorOverride = null; } }); } private sealed class TempLayout : IDisposable { private readonly string _path; public TempLayout() { _path = Path.Combine(Path.GetTempPath(), $"ytLive-desktoplock-{Guid.NewGuid():N}.db"); using (var schema = new LayoutStore(_path)) { } SqliteConnection.ClearAllPools(); MainViewModel.LayoutPathOverride = _path; } public void Dispose() { MainViewModel.LayoutPathOverride = null; SqliteConnection.ClearAllPools(); try { File.Delete(_path); } catch { /* best-effort cleanup */ } } } /// A deterministic stand-in for : /// claims a full-screen window owns the given foreground monitor (or none). #pragma warning disable CS0067 // fullscreen-changed wiring is not part of this seam private sealed class StubFullScreenDetector : IFullScreenDetector { private readonly int? _foregroundMonitor; public StubFullScreenDetector(int? foregroundMonitor) => _foregroundMonitor = foregroundMonitor; public int? GetForegroundFullScreenMonitorIndex() => _foregroundMonitor; public int PrimaryMonitorIndex() => 0; public IReadOnlyList GetDisplays() => Array.Empty(); public event Action? FullscreenMonitorChanged; public void StartWatching() { } public void StopWatching() { } } }