Files
cursor-lang/CursorLang.Tests/Services/LayoutPopupServiceTests.cs
T
2026-08-09 18:31:43 +05:00

213 lines
6.6 KiB
C#

using CursorLang.Models;
using CursorLang.Services;
using CursorLang.Tests.Infrastructure;
using CursorLang.ViewModels;
namespace CursorLang.Tests.Services;
/// <summary>
/// The lifetime of the tooltip. Its timer lives on the interface thread,
/// so everything happens there as well.
/// </summary>
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);
});
}
}