public void HandlersShouldAbstractClass(ILspHandlerTypeDescriptor descriptor) { _logger.LogInformation("Handler: {Type}", descriptor.HandlerType); // This test requires a refactor, the delegating handlers have been removed and replaced by shared implementations // TODO: // * Check for extension methods // * Check for IPartialItem(s)<> extension methods // * Check that the extension method calls `AddHandler` using the correct eventname // * check extension method name // * Also update events to have a nicer fire and forget abstract class // * Ensure all notifications have an action and task returning function var abstractHandler = descriptor.HandlerType.Assembly.ExportedTypes.FirstOrDefault(z => z.IsAbstract && z.IsClass && descriptor.HandlerType.IsAssignableFrom(z)); abstractHandler.Should().NotBeNull($"{descriptor.HandlerType.FullName} is missing abstract base class"); var delegatingHandler = descriptor.HandlerType.Assembly.DefinedTypes.FirstOrDefault(z => abstractHandler.IsAssignableFrom(z) && abstractHandler != z); if (delegatingHandler != null) { _logger.LogInformation("Delegating Handler: {Type}", delegatingHandler); delegatingHandler.DeclaringType.Should().NotBeNull(); delegatingHandler.DeclaringType.GetMethods(BindingFlags.Public | BindingFlags.Static).Any(z => z.Name.StartsWith("On")).Should() .BeTrue($"{descriptor.HandlerType.FullName} is missing delegating extension method"); } }
public MethodMatcher(IEnumerable <Type> registries, ILspHandlerTypeDescriptor descriptor, Type extensionClass, string methodName = null) { _registries = registries; _descriptor = descriptor; _extensionClass = extensionClass; _methodName = methodName; }
public void HandlersShouldHaveExpectedExtensionMethodsBasedOnDirection(ILspHandlerTypeDescriptor descriptor, string onMethodName, string sendMethodName, Type extensionClass, string extensionClassName) { _logger.LogInformation("Handler: {Type} {Extension} {ExtensionName} {OnMethod} {SendMethod}", descriptor.HandlerType, extensionClass, extensionClassName, onMethodName, sendMethodName); var expectedEventRegistries = descriptor.Direction switch { Direction.ClientToServer => new (string type, Func <ParameterInfo, bool> matcher)[] { ("Server", info => info.ParameterType.Name.EndsWith("ServerRegistry")) },
public LspHandlerDescriptor( string method, string key, IJsonRpcHandler handler, Type handlerType, Type @params, Type registrationType, object registrationOptions, Func <bool> allowsDynamicRegistration, Type capabilityType, RequestProcessType?requestProcessType, Action disposeAction, ILspHandlerTypeDescriptor typeDescriptor ) { _disposeAction = disposeAction; Id = Guid.NewGuid(); Method = method; Key = key; ImplementationType = handler.GetType(); Handler = handler; HandlerType = handlerType; Params = @params; RegistrationType = registrationType; RegistrationOptions = registrationOptions; _allowsDynamicRegistration = allowsDynamicRegistration; CapabilityType = capabilityType; Response = typeDescriptor?.ResponseType ?? @params?.GetInterfaces() .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IRequest <>))? .GetGenericArguments()[0] ?? typeof(Unit); // If multiple are implemented this behavior is unknown CanBeResolvedHandlerType = handler.GetType().GetTypeInfo() .ImplementedInterfaces .FirstOrDefault(x => typeof(ICanBeResolvedHandler).IsAssignableFrom(x)); HasReturnType = Response != null && Response != typeof(Unit); IsDelegatingHandler = @params?.IsGenericType == true && ( typeof(DelegatingRequest <>).IsAssignableFrom(@params.GetGenericTypeDefinition()) || typeof(DelegatingNotification <>).IsAssignableFrom(@params.GetGenericTypeDefinition()) ); IsNotification = typeof(IJsonRpcNotificationHandler).IsAssignableFrom(handlerType) || handlerType .GetInterfaces().Any( z => z.IsGenericType && typeof(IJsonRpcNotificationHandler <>).IsAssignableFrom( z.GetGenericTypeDefinition() ) ); IsRequest = !IsNotification; RequestProcessType = requestProcessType; TypeDescriptor = typeDescriptor; }
public void HandlersShouldExtensionMethodClassWithMethods(ILspHandlerTypeDescriptor descriptor, string onMethodName, string sendMethodName, Type extensionClass, string extensionClassName) { // This test requires a refactor, the delegating handlers have been removed and replaced by shared implementations // TODO: // * Check for IPartialItem(s)<> extension methods // * Also update events to have a nicer fire and forget abstract class _logger.LogInformation("Handler: {Type} {Extension} {ExtensionName} {OnMethod} {SendMethod}", descriptor.HandlerType, extensionClass, extensionClassName, onMethodName, sendMethodName); extensionClass.Should().NotBeNull($"{descriptor.HandlerType.FullName} is missing extension method class"); extensionClass.GetMethods().Any(z => z.Name == onMethodName && typeof(IJsonRpcHandlerRegistry).IsAssignableFrom(z.GetParameters()[0].ParameterType)).Should() .BeTrue($"{descriptor.HandlerType.FullName} is missing event extension methods named {onMethodName}"); extensionClass.GetMethods().Any(z => z.Name == sendMethodName && typeof(IResponseRouter).IsAssignableFrom(z.GetParameters()[0].ParameterType)).Should() .BeTrue($"{descriptor.HandlerType.FullName} is missing execute extension methods named {sendMethodName}"); var registries = extensionClass.GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(z => z.Name == onMethodName || z.Name == sendMethodName) .Select(z => z.GetParameters()[0].ParameterType) .Distinct() .ToHashSet(); if (descriptor.Direction == Direction.Bidirectional) { registries .Where(z => typeof(IClientProxy).IsAssignableFrom(z) || typeof(ILanguageServerRegistry).IsAssignableFrom(z)) .Should().HaveCountGreaterOrEqualTo(1, $"{descriptor.HandlerType.FullName} there should be methods for both handing the event and sending the event"); registries .Where(z => typeof(IServerProxy).IsAssignableFrom(z) || typeof(ILanguageClientRegistry).IsAssignableFrom(z)) .Should().HaveCountGreaterOrEqualTo(1, $"{descriptor.HandlerType.FullName} there should be methods for both handing the event and sending the event"); } else if (descriptor.Direction == Direction.ServerToClient) { registries .Where(z => typeof(IServerProxy).IsAssignableFrom(z) || typeof(ILanguageClientRegistry).IsAssignableFrom(z)) .Should().HaveCountGreaterOrEqualTo(1, $"{descriptor.HandlerType.FullName} there should be methods for both handing the event and sending the event"); registries .Where(z => typeof(IClientProxy).IsAssignableFrom(z) || typeof(ILanguageServerRegistry).IsAssignableFrom(z)) .Should().HaveCount(0, $"{descriptor.HandlerType.FullName} must not cross the streams or be made bidirectional"); } else if (descriptor.Direction == Direction.ClientToServer) { registries .Where(z => typeof(IClientProxy).IsAssignableFrom(z) || typeof(ILanguageServerRegistry).IsAssignableFrom(z)) .Should().HaveCountGreaterOrEqualTo(1, $"{descriptor.HandlerType.FullName} there should be methods for both handing the event and sending the event"); registries .Where(z => typeof(IServerProxy).IsAssignableFrom(z) || typeof(ILanguageClientRegistry).IsAssignableFrom(z)) .Should().HaveCount(0, $"{descriptor.HandlerType.FullName} must not cross the streams or be made bidirectional"); } }
public void HandlersShouldAbstractClass(ILspHandlerTypeDescriptor descriptor) { _logger.LogInformation("Handler: {Type}", descriptor.HandlerType); // This test requires a refactor, the delegating handlers have been removed and replaced by shared implementations var abstractHandler = descriptor.HandlerType.Assembly.ExportedTypes.FirstOrDefault(z => z.IsAbstract && z.IsClass && descriptor.HandlerType.IsAssignableFrom(z)); abstractHandler.Should().NotBeNull($"{descriptor.HandlerType.FullName} is missing abstract base class"); var delegatingHandler = descriptor.HandlerType.Assembly.DefinedTypes.FirstOrDefault( z => abstractHandler.IsAssignableFrom(z) && abstractHandler != z && !z.IsGenericTypeDefinition ); if (delegatingHandler != null) { _logger.LogInformation("Delegating Handler: {Type}", delegatingHandler); delegatingHandler.DeclaringType.Should().NotBeNull(); delegatingHandler.DeclaringType !.GetMethods(BindingFlags.Public | BindingFlags.Static).Any(z => z.Name.StartsWith("On")).Should() .BeTrue($"{descriptor.HandlerType.FullName} is missing delegating extension method"); } }