Files
cursor-lang/CursorLang.Tests.Shared/Fakes.cs
T
alex 55ac8e6556 lightweight variant (#1)
Reviewed-on: #1
Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
2026-08-12 13:37:30 +00:00

270 lines
6.9 KiB
C#

using System.ComponentModel;
using CursorLang.Core.Models;
using CursorLang.Core.Services;
namespace CursorLang.Tests.Shared;
/// <summary>
/// The keyboard layout, with the test in charge of it.
/// </summary>
public sealed class FakeKeyboardLayoutService : IKeyboardLayoutService
{
public int StartCalls { get; private set; }
public int StopCalls { get; private set; }
public int SwitchCalls { get; private set; }
public KeyboardLayout CurrentLayout { get; set; } = KeyboardLayout.FromLocaleId(0x0409);
public KeyboardLayout Current => CurrentLayout;
public event EventHandler<LayoutChangedEventArgs>? LayoutChanged;
public void Start() => StartCalls++;
public void Stop() => StopCalls++;
public void SwitchToNext() => SwitchCalls++;
public void RaiseLayoutChanged(KeyboardLayout layout, LayoutChangeReason reason) =>
LayoutChanged?.Invoke(this, new LayoutChangedEventArgs(layout, reason));
public bool HasSubscribers => LayoutChanged is not null;
}
/// <summary>
/// A tooltip that pops up nowhere and merely remembers what it was asked for.
/// </summary>
public sealed class FakeLayoutPopupService : ILayoutPopupService
{
public List<KeyboardLayout> Shown { get; } = [];
public List<KeyboardLayout> ShownUntilHidden { get; } = [];
public int HideCalls { get; private set; }
public void Show(KeyboardLayout layout) => Shown.Add(layout);
public void ShowUntilHidden(KeyboardLayout layout) => ShownUntilHidden.Add(layout);
public void Hide() => HideCalls++;
}
/// <summary>
/// The Caps Lock interception without intercepting anything: the test supplies the presses.
/// </summary>
public sealed class FakeCapsLockHotkeyService : ICapsLockHotkeyService
{
public event EventHandler? Tapped;
public event EventHandler? HoldStarted;
public event EventHandler? HoldEnded;
public bool IsRunning { get; private set; }
public int StartCalls { get; private set; }
public int StopCalls { get; private set; }
public void Start()
{
StartCalls++;
IsRunning = true;
}
public void Stop()
{
StopCalls++;
IsRunning = false;
}
public void RaiseTapped() => Tapped?.Invoke(this, EventArgs.Empty);
public void RaiseHoldStarted() => HoldStarted?.Invoke(this, EventArgs.Empty);
public void RaiseHoldEnded() => HoldEnded?.Invoke(this, EventArgs.Empty);
public bool HasSubscribers => Tapped is not null || HoldStarted is not null || HoldEnded is not null;
}
/// <summary>
/// Startup whose state the test assigns.
/// </summary>
public sealed class FakeStartupService : IStartupService
{
public StartupState State { get; set; } = StartupState.Disabled;
public StartupState? AnswerOnEnable { get; set; }
public List<bool> Requests { get; } = [];
public int GetStateCalls { get; private set; }
public Task<StartupState> GetStateAsync()
{
GetStateCalls++;
return Task.FromResult(State);
}
public Task<StartupState> SetEnabledAsync(bool enabled)
{
Requests.Add(enabled);
State = enabled
? AnswerOnEnable ?? StartupState.Enabled
: StartupState.Disabled;
return Task.FromResult(State);
}
}
/// <summary>
/// Releases the test writes itself, with no repository behind them.
/// </summary>
public sealed class FakeUpdateService : IUpdateService
{
public ReleaseInfo? Release { get; set; }
public Exception? Failure { get; set; }
public TaskCompletionSource? DownloadGate { get; set; }
public string PackagePath { get; set; } = string.Empty;
public int CheckCalls { get; private set; }
public List<string> Installed { get; } = [];
public bool IsSupported { get; set; } = true;
public Version CurrentVersion { get; set; } = new(1, 0, 0, 0);
public Task<ReleaseInfo?> CheckAsync(CancellationToken cancellationToken)
{
CheckCalls++;
return Failure is null
? Task.FromResult(Release)
: Task.FromException<ReleaseInfo?>(Failure);
}
public async Task<string> DownloadAsync(
ReleaseInfo release,
IProgress<double>? progress,
CancellationToken cancellationToken)
{
if (DownloadGate is not null)
{
await DownloadGate.Task.WaitAsync(cancellationToken);
}
if (Failure is not null)
{
throw Failure;
}
progress?.Report(0.5);
return PackagePath;
}
public void Install(string packagePath) => Installed.Add(packagePath);
}
/// <summary>
/// A release list the test fills in, with no repository behind it.
/// </summary>
public sealed class FakeReleaseFeed : IReleaseFeed
{
public ReleaseInfo? Release { get; set; }
public Exception? Failure { get; set; }
public List<HttpRequestMessage> Authorized { get; } = [];
public Task<ReleaseInfo?> GetLatestAsync(CancellationToken cancellationToken) =>
Failure is null ? Task.FromResult(Release) : Task.FromException<ReleaseInfo?>(Failure);
public void Authorize(HttpRequestMessage request) => Authorized.Add(request);
}
/// <summary>
/// Interface strings without resources: the key comes back as is, tagged with the language.
/// </summary>
public sealed class FakeLocalizationService : ILocalizationService
{
private string _currentLanguage = "en";
public event PropertyChangedEventHandler? PropertyChanged;
public List<string> RequestedKeys { get; } = [];
public string this[string key]
{
get
{
RequestedKeys.Add(key);
return $"{_currentLanguage}:{key}";
}
}
public IReadOnlyList<LanguageOption> AvailableLanguages { get; } =
[
new("en", "English"),
new("ru", "Русский"),
];
public string CurrentLanguage
{
get => _currentLanguage;
set
{
if (string.IsNullOrWhiteSpace(value) || value == _currentLanguage)
{
return;
}
_currentLanguage = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentLanguage)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(LocalizationService.IndexerName));
}
}
}
/// <summary>
/// A tooltip window that shows nothing.
/// </summary>
public sealed class FakeLayoutPopupWindow : ILayoutPopupWindow
{
public int ShowCalls { get; private set; }
public int HideCalls { get; private set; }
public int CloseCalls { get; private set; }
public List<string> Calls { get; } = [];
public string? ShownText { get; private set; }
public void ShowPopup(string shortName)
{
ShowCalls++;
ShownText = shortName;
Calls.Add("show");
}
public void Hide()
{
HideCalls++;
Calls.Add("hide");
}
public void Close()
{
CloseCalls++;
Calls.Add("close");
}
}