Files
LlamaCasty/ytLive.Tests/GlobalHotkeyTests.cs
T

94 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Xunit;
using ytLive.Services;
namespace ytLive.Tests;
/// <summary>
/// TASK 20 integration: global hotkeys reach their commands. A real MainWindow
/// attaches the GlobalHotkeyManager (fake registrar — no OS-wide registration in
/// tests); posting a genuine WM_HOTKEY through the window's own HwndSource hook
/// must stage the mapped scene and flip the mic mute. Closing must revoke every
/// registration made.
/// </summary>
[Collection("RealApp")]
public sealed class GlobalHotkeyTests : IDisposable
{
[Fact]
public void WmHotkey_StagesScene_And_TogglesMic_And_RevokesOnClose()
{
_app.Run(Run);
}
private readonly RealAppHost _app;
public GlobalHotkeyTests(RealAppHost app) => _app = app;
private sealed class FakeRegistrar : IHotkeyRegistrar
{
public readonly List<HotkeyId> Registered = new();
public readonly List<HotkeyId> Unregistered = new();
public bool Register(IntPtr hwnd, HotkeyId id, uint modifiers, uint virtualKey)
{
Registered.Add(id);
return true;
}
public void Unregister(IntPtr hwnd, HotkeyId id) => Unregistered.Add(id);
}
private void Run()
{
var tempDb = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"ytLlive-hotkeys-{Guid.NewGuid():N}.db");
ViewModels.MainViewModel.LayoutPathOverride = tempDb;
GlobalHotkeyManager.RegistrarOverride = () => _registrar;
var window = default(MainWindow);
try
{
using (var schema = new ytLive.Services.LayoutStore(tempDb)) { }
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
window = new MainWindow();
var vm = (ViewModels.MainViewModel)window.DataContext;
new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle();
var hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
Assert.Equal(Enum.GetValues(typeof(HotkeyId)).Length, _registrar.Registered.Count);
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.SceneBrb, IntPtr.Zero);
Assert.NotNull(vm.StagedScene);
Assert.Equal("BRB", vm.StagedScene!.Name);
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.SceneLive, IntPtr.Zero);
Assert.Equal("Live", vm.StagedScene!.Name);
var wasMuted = vm.MicMuted;
SendMessage(hwnd, GlobalHotkeyManager.WM_HOTKEY, (IntPtr)HotkeyId.ToggleMicMute, IntPtr.Zero);
Assert.NotEqual(wasMuted, vm.MicMuted);
window.Close();
window = null;
Assert.Equal(_registrar.Registered.Count, _registrar.Unregistered.Count);
}
finally
{
window?.Close();
GlobalHotkeyManager.RegistrarOverride = null;
ViewModels.MainViewModel.LayoutPathOverride = null;
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
try { System.IO.File.Delete(tempDb); } catch { /* best-effort cleanup */ }
}
}
private readonly FakeRegistrar _registrar = new();
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public void Dispose() => GC.SuppressFinalize(this);
}