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")) },
Esempio n. 4
0
        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");
            }
        }