using CursorLang.Models; using CursorLang.Services; using CursorLang.Tests.Infrastructure; using CursorLang.ViewModels; namespace CursorLang.Tests.Services; /// /// The lifetime of the tooltip. Its timer lives on the interface thread, /// so everything happens there as well. /// public sealed class LayoutPopupServiceTests { private static readonly KeyboardLayout Russian = KeyboardLayout.FromLocaleId(0x0419); private static readonly KeyboardLayout English = KeyboardLayout.FromLocaleId(0x0409); [Fact] public void Showing_puts_out_the_short_name_of_the_layout() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 10_000 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); }); Assert.Equal("RU", viewModel.ShortName); Assert.Equal(1, window.ShowCalls); } [Fact] public void The_tooltip_goes_away_once_its_time_is_up() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 30 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); Assert.Equal(0, window.HideCalls); Sta.WaitFor(() => window.HideCalls == 1, "the tooltip hid itself"); }); } // The duration is read on every show: it is edited in the settings on the fly [Fact] public void A_new_duration_takes_effect_from_the_next_show() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 10_000 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); settings.DurationMilliseconds = 30; service.Show(English); Sta.WaitFor(() => window.HideCalls == 1, "the tooltip hid by the new duration"); }); } // Quick switching must not cut the tooltip off mid-word [Fact] public void Showing_again_extends_the_time_on_screen() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 60 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); for (int i = 0; i < 5; i++) { service.Show(i % 2 == 0 ? Russian : English); Sta.Pause(TimeSpan.FromMilliseconds(20)); Assert.Equal(0, window.HideCalls); } Sta.WaitFor(() => window.HideCalls == 1, "the tooltip hid after the last show"); }); } [Fact] public void A_show_until_hidden_does_not_hide_by_itself() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 20 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.ShowUntilHidden(Russian); Sta.Pause(TimeSpan.FromMilliseconds(80)); Assert.Equal(1, window.ShowCalls); Assert.Equal(0, window.HideCalls); service.Hide(); Assert.Equal(1, window.HideCalls); }); } // A show until hidden on top of an ordinary one also cancels the countdown [Fact] public void A_show_until_hidden_stops_a_running_countdown() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 30 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); service.ShowUntilHidden(English); Sta.Pause(TimeSpan.FromMilliseconds(100)); Assert.Equal(0, window.HideCalls); Assert.Equal("EN", viewModel.ShortName); }); } [Fact] public void Hiding_cancels_a_running_countdown() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 30 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); service.Hide(); Sta.Pause(TimeSpan.FromMilliseconds(100)); // There must be no second hide from the timer Assert.Equal(1, window.HideCalls); }); } [Fact] public void Closing_the_service_closes_the_window() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings(); var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); service.Dispose(); Sta.Pause(TimeSpan.FromMilliseconds(50)); }); Assert.Equal(1, window.CloseCalls); } [Fact] public void After_the_service_is_closed_the_timer_stays_silent() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 20 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); service.Dispose(); Sta.Pause(TimeSpan.FromMilliseconds(80)); Assert.Equal(0, window.HideCalls); }); } [Fact] public void Showing_always_comes_before_hiding() { var window = new FakeLayoutPopupWindow(); var settings = new AppSettings { DurationMilliseconds = 20 }; var viewModel = new LayoutPopupViewModel(settings); Sta.Run(() => { using var service = new LayoutPopupService(window, viewModel, settings); service.Show(Russian); Sta.WaitFor(() => window.HideCalls == 1, "the tooltip hid itself"); Assert.Equal(["show", "hide"], window.Calls); }); } }