using System.Reflection; using Microsoft.Extensions.Configuration; namespace ScadaLink.Host.Tests; public class OptionsTests { /// /// Verify no component library (excluding Host) uses IConfiguration or accepts it /// in its AddXxx() extension method. Component libraries should only depend on /// DI abstractions and Options pattern, not on Configuration directly. /// [Fact] public void ComponentLibraries_DoNotAcceptIConfigurationInAddMethods() { // All component assemblies (excluding Host itself and Commons) var componentAssemblies = new[] { typeof(ClusterInfrastructure.ServiceCollectionExtensions).Assembly, typeof(Communication.ServiceCollectionExtensions).Assembly, typeof(HealthMonitoring.ServiceCollectionExtensions).Assembly, typeof(ExternalSystemGateway.ServiceCollectionExtensions).Assembly, typeof(NotificationService.ServiceCollectionExtensions).Assembly, typeof(TemplateEngine.ServiceCollectionExtensions).Assembly, typeof(DeploymentManager.ServiceCollectionExtensions).Assembly, typeof(Security.ServiceCollectionExtensions).Assembly, typeof(ConfigurationDatabase.ServiceCollectionExtensions).Assembly, typeof(SiteRuntime.ServiceCollectionExtensions).Assembly, typeof(DataConnectionLayer.ServiceCollectionExtensions).Assembly, typeof(StoreAndForward.ServiceCollectionExtensions).Assembly, typeof(SiteEventLogging.ServiceCollectionExtensions).Assembly, typeof(CentralUI.ServiceCollectionExtensions).Assembly, typeof(InboundAPI.ServiceCollectionExtensions).Assembly, }; foreach (var assembly in componentAssemblies) { // Check that the assembly does not reference Microsoft.Extensions.Configuration var configRef = assembly.GetReferencedAssemblies() .FirstOrDefault(a => a.Name == "Microsoft.Extensions.Configuration.Abstractions"); // Find all public static extension methods named Add* var extensionClasses = assembly.GetExportedTypes() .Where(t => t.IsClass && t.IsAbstract && t.IsSealed); // static classes foreach (var cls in extensionClasses) { var addMethods = cls.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.Name.StartsWith("Add") || m.Name.StartsWith("Map")); foreach (var method in addMethods) { var parameters = method.GetParameters(); foreach (var param in parameters) { Assert.False( typeof(IConfiguration).IsAssignableFrom(param.ParameterType), $"{assembly.GetName().Name}: {cls.Name}.{method.Name} accepts IConfiguration parameter '{param.Name}'. " + "Component libraries should use the Options pattern, not IConfiguration."); } } } } } }