using CursorLang.Models; using CursorLang.Services; using CursorLang.ViewModels; using CursorLang.Views; using Microsoft.Extensions.DependencyInjection; namespace CursorLang.Tests; /// /// What the container is made of. The tests cannot build the application whole /// — it would raise windows and take the place of the single instance — but /// checking that everything needed is declared and resolvable works without that. /// public sealed class AppTests { [Theory] [InlineData(typeof(SettingsService))] [InlineData(typeof(ThemeService))] [InlineData(typeof(IThemeService))] [InlineData(typeof(MainWindowPlacement))] [InlineData(typeof(ILocalizationService))] [InlineData(typeof(IStartupService))] [InlineData(typeof(IUpdateService))] [InlineData(typeof(UpdateOptions))] [InlineData(typeof(IKeyboardLayoutService))] [InlineData(typeof(ILayoutPopupService))] [InlineData(typeof(ICapsLockHotkeyService))] [InlineData(typeof(ILayoutPopupWindow))] [InlineData(typeof(LayoutNotificationCoordinator))] [InlineData(typeof(CapsLockSwitchCoordinator))] [InlineData(typeof(LayoutPopupViewModel))] [InlineData(typeof(SettingsViewModel))] [InlineData(typeof(UpdateViewModel))] [InlineData(typeof(LayoutPopupWindow))] [InlineData(typeof(MainWindow))] [InlineData(typeof(KeyboardLayoutOptions))] [InlineData(typeof(AppSettings))] public void Everything_the_app_needs_is_declared_in_the_container(Type service) { Assert.Contains(Describe(), descriptor => descriptor.ServiceType == service); } // The settings, the tooltip and the layout watch have to be shared by the // whole application: a second copy of them would mean a second // tooltip or lost settings [Fact] public void Everything_in_the_container_is_declared_as_a_single_copy() { Assert.All(Describe(), descriptor => Assert.Equal(ServiceLifetime.Singleton, descriptor.Lifetime)); } [Fact] public void Every_service_is_declared_once() { var types = Describe().Select(descriptor => descriptor.ServiceType).ToList(); Assert.Equal(types.Count, types.Distinct().Count()); } /// /// The dependencies of every service have to be resolvable. The check runs /// while the container is built and creates no services itself. /// [Fact] public void The_service_dependencies_come_together_with_nothing_missing() { var services = new ServiceCollection(); App.ConfigureServices(services); ServiceProvider provider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true, }); // Ensure the provider was built successfully — this serves as an assertion // so the test framework recognizes this as a meaningful test. Assert.NotNull(provider); provider.Dispose(); } [Fact] public void The_settings_come_from_the_settings_service() { ServiceDescriptor settings = Describe() .Single(descriptor => descriptor.ServiceType == typeof(AppSettings)); // The settings are not created anew but read from disk by the service Assert.NotNull(settings.ImplementationFactory); } [Fact] public void The_tooltip_window_and_its_interface_are_one_window() { ServiceDescriptor window = Describe() .Single(descriptor => descriptor.ServiceType == typeof(ILayoutPopupWindow)); Assert.NotNull(window.ImplementationFactory); } [Fact] public void The_theme_and_its_interface_are_one_service() { ServiceDescriptor theme = Describe() .Single(descriptor => descriptor.ServiceType == typeof(IThemeService)); Assert.NotNull(theme.ImplementationFactory); } private static ServiceCollection Describe() { var services = new ServiceCollection(); App.ConfigureServices(services); return services; } }