From 9c06b078ca12107b563c4689de40e20609bac0ca Mon Sep 17 00:00:00 2001 From: Shane32 Date: Sun, 21 Mar 2021 21:57:55 -0400 Subject: [PATCH 01/31] Upgrade to v4 --- src/ContextWrapper.cs | 121 --------------------------- src/DIDocumentExecuter.cs | 31 ++++--- src/DIExecutionStrategy.cs | 2 + src/DIObjectGraphType.cs | 111 +++++++++++++----------- src/ResolveFieldContextAdapter.cs | 73 ---------------- src/ResolveFieldContextExtensions.cs | 13 --- src/ScopedFieldResolver.cs | 41 --------- src/Shane32.GraphQL.DI.csproj | 3 +- 8 files changed, 84 insertions(+), 311 deletions(-) delete mode 100644 src/ContextWrapper.cs delete mode 100644 src/ResolveFieldContextAdapter.cs delete mode 100644 src/ResolveFieldContextExtensions.cs delete mode 100644 src/ScopedFieldResolver.cs diff --git a/src/ContextWrapper.cs b/src/ContextWrapper.cs deleted file mode 100644 index 11d1809..0000000 --- a/src/ContextWrapper.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using GraphQL.Instrumentation; -using GraphQL.Language.AST; -using GraphQL.Types; - -namespace GraphQL.DI -{ - internal class ContextWrapper : IResolveFieldContext - { - private readonly IResolveFieldContext _baseContext; - - public ContextWrapper(IResolveFieldContext baseContext, IServiceProvider serviceProvider) - { - _baseContext = baseContext ?? throw new ArgumentNullException(nameof(baseContext)); - RequestServices = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - } - - public T Source => _baseContext.Source; - - public string FieldName => _baseContext.FieldName; - - public Language.AST.Field FieldAst => _baseContext.FieldAst; - - public FieldType FieldDefinition => _baseContext.FieldDefinition; - - public IGraphType ReturnType => _baseContext.ReturnType; - - public IObjectGraphType ParentType => _baseContext.ParentType; - - public IDictionary Arguments => _baseContext.Arguments; - - public object RootValue => _baseContext.RootValue; - - public ISchema Schema => _baseContext.Schema; - - public Document Document => _baseContext.Document; - - public Operation Operation => _baseContext.Operation; - - public Fragments Fragments => _baseContext.Fragments; - - public Variables Variables => _baseContext.Variables; - - public CancellationToken CancellationToken => _baseContext.CancellationToken; - - public Metrics Metrics => _baseContext.Metrics; - - public ExecutionErrors Errors => _baseContext.Errors; - - public IEnumerable Path => _baseContext.Path; - - public IEnumerable ResponsePath => _baseContext.ResponsePath; - - public IDictionary SubFields => _baseContext.SubFields; - - public IDictionary Extensions => _baseContext.Extensions; - - public IServiceProvider RequestServices { get; } - - public IDictionary UserContext => _baseContext.UserContext; - - object IResolveFieldContext.Source => ((IResolveFieldContext)_baseContext).Source; - } - - internal class ContextWrapper : IResolveFieldContext - { - private readonly IResolveFieldContext _baseContext; - - public ContextWrapper(IResolveFieldContext baseContext, IServiceProvider serviceProvider) - { - _baseContext = baseContext ?? throw new ArgumentNullException(nameof(baseContext)); - RequestServices = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - } - - public string FieldName => _baseContext.FieldName; - - public Language.AST.Field FieldAst => _baseContext.FieldAst; - - public FieldType FieldDefinition => _baseContext.FieldDefinition; - - public IGraphType ReturnType => _baseContext.ReturnType; - - public IObjectGraphType ParentType => _baseContext.ParentType; - - public IDictionary Arguments => _baseContext.Arguments; - - public object RootValue => _baseContext.RootValue; - - public object Source => _baseContext.Source; - - public ISchema Schema => _baseContext.Schema; - - public Document Document => _baseContext.Document; - - public Operation Operation => _baseContext.Operation; - - public Fragments Fragments => _baseContext.Fragments; - - public Variables Variables => _baseContext.Variables; - - public CancellationToken CancellationToken => _baseContext.CancellationToken; - - public Metrics Metrics => _baseContext.Metrics; - - public ExecutionErrors Errors => _baseContext.Errors; - - public IEnumerable Path => _baseContext.Path; - - public IEnumerable ResponsePath => _baseContext.ResponsePath; - - public IDictionary SubFields => _baseContext.SubFields; - - public IDictionary Extensions => _baseContext.Extensions; - - public IServiceProvider RequestServices { get; } - - public IDictionary UserContext => _baseContext.UserContext; - } -} diff --git a/src/DIDocumentExecuter.cs b/src/DIDocumentExecuter.cs index e6dc1e8..eb8b2ce 100644 --- a/src/DIDocumentExecuter.cs +++ b/src/DIDocumentExecuter.cs @@ -3,31 +3,40 @@ using GraphQL.Language.AST; using GraphQL.Validation; using GraphQL.Validation.Complexity; +using Microsoft.Extensions.DependencyInjection; namespace GraphQL.DI { - //DIDocumentExecuter and DIExecutionStrategy are designed to be registered as scoped service providers + //DIDocumentExecuter is designed to be registered as a singleton public class DIDocumentExecuter : DocumentExecuter { - protected DIExecutionStrategy DIExecutionStrategy; - protected SubscriptionExecutionStrategy SubscriptionExecutionStrategy; + protected IExecutionStrategy DIExecutionStrategy = DI.DIExecutionStrategy.Instance; + protected IExecutionStrategy SubscriptionExecutionStrategy = null; public DIDocumentExecuter() : base() { - DIExecutionStrategy = new DIExecutionStrategy(); - SubscriptionExecutionStrategy = new SubscriptionExecutionStrategy(); } - //pull IDocumentBuilder, IDocumentValidator, IComplexityAnalyzer, DIExecutionStrategy, and SubscriptionExecutionStrategy from DI if they have been registered + public DIDocumentExecuter(IExecutionStrategy subscriptionExecutionStrategy) : base() + { + SubscriptionExecutionStrategy = subscriptionExecutionStrategy; + } + + //pull IDocumentBuilder, IDocumentValidator, and IComplexityAnalyzer from DI if they have been registered //if any of them have not been registered, use default implementations public DIDocumentExecuter( IServiceProvider serviceProvider) : base( - (IDocumentBuilder)(serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider))).GetService(typeof(IDocumentBuilder)) ?? new GraphQLDocumentBuilder(), - (IDocumentValidator)serviceProvider.GetService(typeof(IDocumentValidator)) ?? new DocumentValidator(), - (IComplexityAnalyzer)serviceProvider.GetService(typeof(IComplexityAnalyzer)) ?? new ComplexityAnalyzer()) + (serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider))).GetService() ?? new GraphQLDocumentBuilder(), + serviceProvider.GetService() ?? new DocumentValidator(), + serviceProvider.GetService() ?? new ComplexityAnalyzer()) + { + } + + //pull IDocumentBuilder, IDocumentValidator, and IComplexityAnalyzer from DI if they have been registered + //if any of them have not been registered, use default implementations + public DIDocumentExecuter(IServiceProvider serviceProvider, IExecutionStrategy subscriptionExecutionStrategy) : this(serviceProvider) { - DIExecutionStrategy = (DIExecutionStrategy)serviceProvider.GetService(typeof(DIExecutionStrategy)) ?? new DIExecutionStrategy(); - SubscriptionExecutionStrategy = (SubscriptionExecutionStrategy)serviceProvider.GetService(typeof(SubscriptionExecutionStrategy)) ?? new SubscriptionExecutionStrategy(); + SubscriptionExecutionStrategy = subscriptionExecutionStrategy; } protected override IExecutionStrategy SelectExecutionStrategy(ExecutionContext context) diff --git a/src/DIExecutionStrategy.cs b/src/DIExecutionStrategy.cs index f55ed6b..04fe013 100644 --- a/src/DIExecutionStrategy.cs +++ b/src/DIExecutionStrategy.cs @@ -9,6 +9,8 @@ namespace GraphQL.DI { public class DIExecutionStrategy : ExecutionStrategy { + internal static DIExecutionStrategy Instance = new DIExecutionStrategy(); + protected override async Task ExecuteNodeTreeAsync(ExecutionContext context, ObjectExecutionNode rootNode) { Func> taskFunc = async (task, node) => { await task; return node; }; diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index 2d7c2f1..163d1e8 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -6,6 +7,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using GraphQL.MicrosoftDI; using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; @@ -41,12 +43,12 @@ public DIObjectGraphType() } //grab some methods via reflection for us to use later - private static readonly MethodInfo getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(ServiceProviderServiceExtensions.GetRequiredService) && !x.IsGenericMethod); - private static readonly MethodInfo asMethod = typeof(ResolveFieldContextExtensions).GetMethod(nameof(ResolveFieldContextExtensions.As), BindingFlags.Static | BindingFlags.Public); - private static readonly MethodInfo getArgumentMethod = typeof(GraphQL.ResolveFieldContextExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(GraphQL.ResolveFieldContextExtensions.GetArgument) && x.IsGenericMethod); - private static readonly PropertyInfo sourceProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.Source), BindingFlags.Instance | BindingFlags.Public); - private static readonly PropertyInfo requestServicesProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.RequestServices), BindingFlags.Instance | BindingFlags.Public); - private static readonly PropertyInfo cancellationTokenProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.CancellationToken), BindingFlags.Public | BindingFlags.Instance); + private static readonly MethodInfo _getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(ServiceProviderServiceExtensions.GetRequiredService) && !x.IsGenericMethod); + private static readonly MethodInfo _asMethod = typeof(ResolveFieldContextExtensions).GetMethod(nameof(ResolveFieldContextExtensions.As), BindingFlags.Static | BindingFlags.Public); + private static readonly MethodInfo _getArgumentMethod = typeof(ResolveFieldContextExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(ResolveFieldContextExtensions.GetArgument) && x.IsGenericMethod); + private static readonly PropertyInfo _sourceProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.Source), BindingFlags.Instance | BindingFlags.Public); + private static readonly PropertyInfo _requestServicesProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.RequestServices), BindingFlags.Instance | BindingFlags.Public); + private static readonly PropertyInfo _cancellationTokenProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.CancellationToken), BindingFlags.Public | BindingFlags.Instance); protected virtual List CreateFieldTypeList() { @@ -101,33 +103,31 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) //add the constructed expression to the list to be used for creating the resolve function executeParams.Add(expr); } - //define the resolve function - Func resolverFunc; + //check if this is an async method + var isAsync = typeof(Task).IsAssignableFrom(method.ReturnType); + //define the resolve expression + Expression exprResolve; if (method.IsStatic) { //for static methods, no need to pull an instance of the class from the service provider //just call the static method with the executeParams as the parameters - Expression exprResolve = Expression.Convert(Expression.Call(method, executeParams.ToArray()), typeof(object)); - //compile the function and save it as our resolve function - resolverFunc = Expression.Lambda>(exprResolve, resolveFieldContextParameter).Compile(); + exprResolve = Expression.Call(method, executeParams.ToArray()); } else { //for instance methods, pull an instance of the class from the service provider Expression exprGetService = GetInstanceExpression(resolveFieldContextParameter); //then, call the method with the executeParams as the parameters - Expression exprResolve = Expression.Convert(Expression.Call(exprGetService, method, executeParams.ToArray()), typeof(object)); - //compile the function and save it as our resolve function - resolverFunc = Expression.Lambda>(exprResolve, resolveFieldContextParameter).Compile(); + exprResolve = Expression.Call(exprGetService, method, executeParams.ToArray()); } //determine if this should run concurrently with other resolvers //if it's an async static method that does not pull from services, then it's safe to run concurrently - if (typeof(Task).IsAssignableFrom(method.ReturnType) && method.IsStatic && !anyParamsUseServices) { + if (isAsync && method.IsStatic && !anyParamsUseServices) { //mark this field as concurrent, so the execution strategy will run it asynchronously concurrent = true; //set the resolver to run the compiled resolve function - resolver = CreateUnscopedResolver(resolverFunc); + resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); } //for methods that return a Task and are marked with the Concurrent attribute, - else if (typeof(Task).IsAssignableFrom(method.ReturnType) && method.GetCustomAttributes().Any()) { + else if (isAsync && method.GetCustomAttributes().Any()) { //mark this field as concurrent, so the execution strategy will run it asynchronously concurrent = true; //determine if a new DI scope is required @@ -135,16 +135,16 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) //the resolve function needs to create a scope, // then run the compiled resolve function (which creates an instance of the class), // then release the scope once the task has been awaited - resolver = CreateScopedResolver(resolverFunc); + resolver = CreateScopedResolver(exprResolve, resolveFieldContextParameter); } else { //just run the compiled resolve function, and count on the method to handle multithreading issues - resolver = CreateUnscopedResolver(resolverFunc); + resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); } } //for non-async methods, and instance methods that are not marked with the Concurrent attribute else { //just run the compiled resolve function - resolver = CreateUnscopedResolver(resolverFunc); + resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); } } @@ -172,13 +172,8 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) string description = method.GetCustomAttribute()?.Description; //load the deprecation reason string obsoleteDescription = method.GetCustomAttribute()?.Message; - //load the metadata - var metadata = new Dictionary(); - foreach (var metaAttribute in method.GetCustomAttributes()) - metadata.Add(metaAttribute.Key, metaAttribute.Value); - //create the field - return new DIFieldType() { + var fieldType = new DIFieldType() { Type = graphType, ResolvedType = graphTypeResolved, Name = methodName, @@ -187,20 +182,24 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) Description = description, Concurrent = concurrent, DeprecationReason = obsoleteDescription, - Metadata = metadata, }; + //load the metadata + foreach (var metaAttribute in method.GetCustomAttributes()) + fieldType.WithMetadata(metaAttribute.Key, metaAttribute.Value); + //return the field + return fieldType; } } protected virtual Type InferInputGraphType(Type type, bool isRequired) { - return type.GetGraphTypeFromType(!isRequired); + return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.InputType); } protected virtual Type InferOutputGraphType(Type type, bool isRequired) { - return type.GetGraphTypeFromType(!isRequired); + return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.OutputType); } protected virtual Expression GetInstanceExpression(ParameterExpression resolveFieldContextParameter) @@ -211,35 +210,45 @@ protected virtual Expression GetInstanceExpression(ParameterExpression resolveFi protected virtual Expression GetServiceProviderExpression(ParameterExpression resolveFieldContextParameter) { //returns: context.RequestServices - return Expression.Property(resolveFieldContextParameter, requestServicesProperty); + return Expression.Property(resolveFieldContextParameter, _requestServicesProperty); } protected virtual Expression GetServiceExpression(ParameterExpression resolveFieldContextParameter, Type serviceType) { //returns: (serviceType)(context.RequestServices.GetRequiredService(serviceType)) - return Expression.Convert(Expression.Call(getRequiredServiceMethod, GetServiceProviderExpression(resolveFieldContextParameter), Expression.Constant(serviceType)), serviceType); + return Expression.Convert(Expression.Call(_getRequiredServiceMethod, GetServiceProviderExpression(resolveFieldContextParameter), Expression.Constant(serviceType)), serviceType); } - protected virtual IFieldResolver CreateUnscopedResolver(Func resolveFunc) + private ConcurrentDictionary _funcFieldResolverConstructors = new ConcurrentDictionary(); + protected virtual IFieldResolver CreateUnscopedResolver(Expression resolveExpression, ParameterExpression resolveFieldContextParameter) { - return new FuncFieldResolver(resolveFunc); + var constructorInfo = _funcFieldResolverConstructors.GetOrAdd(resolveExpression.Type, t => typeof(FuncFieldResolver<>).MakeGenericType(t).GetConstructors().Single()); + var lambda = Expression.Lambda(resolveExpression, resolveFieldContextParameter).Compile(); + return (IFieldResolver)constructorInfo.Invoke(new[] { lambda }); } - protected virtual IFieldResolver CreateScopedResolver(Func resolverFunc) + private ConcurrentDictionary _scopedFieldResolverConstructors = new ConcurrentDictionary(); + private ConcurrentDictionary _scopedAsyncFieldResolverConstructors = new ConcurrentDictionary(); + protected virtual IFieldResolver CreateScopedResolver(Expression resolveExpression, ParameterExpression resolveFieldContextParameter) { - return new AsyncFieldResolver(async (context) => { - var serviceProvider = context.RequestServices ?? throw new InvalidOperationException("No service provider defined in this context"); - using (var newScope = serviceProvider.CreateScope()) { - context = new ContextWrapper(context, newScope.ServiceProvider); - //run the compiled resolve function, which should return a Task<> - var ret = resolverFunc(context); - if (ret is Task task) { - await task.ConfigureAwait(false); - return task.GetResult(); - } - return ret; //cannot occur, since the return type has already been determined to be a Task<> - } - }); + ConstructorInfo constructorInfo; + if (typeof(Task).IsAssignableFrom(resolveExpression.Type)) { + constructorInfo = _scopedAsyncFieldResolverConstructors.GetOrAdd(GetTaskType(resolveExpression.Type), t => typeof(ScopedAsyncFieldResolver<>).MakeGenericType(t).GetConstructors().Single()); + } else { + constructorInfo = _scopedFieldResolverConstructors.GetOrAdd(resolveExpression.Type, t => typeof(ScopedFieldResolver<>).MakeGenericType(t).GetConstructors().Single()); + } + var lambda = Expression.Lambda(resolveExpression, resolveFieldContextParameter).Compile(); + return (IFieldResolver)constructorInfo.Invoke(new[] { lambda }); + } + + private static Type GetTaskType(Type t) + { + while (t != null) { + if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Task<>)) + return t.GenericTypeArguments[0]; + t = t.BaseType; + } + throw new ArgumentOutOfRangeException(nameof(t), "Type does not inherit from Task<>."); } protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInfo param, ParameterExpression resolveFieldContextParameter, out bool usesServices, out Expression expr) @@ -255,7 +264,7 @@ protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInf } if (param.ParameterType == typeof(CancellationToken)) { //return the cancellation token from the IResolveFieldContext parameter - expr = Expression.MakeMemberAccess(resolveFieldContextParameter, cancellationTokenProperty); + expr = Expression.MakeMemberAccess(resolveFieldContextParameter, _cancellationTokenProperty); //and do not add it as a QueryArgument return null; } @@ -265,7 +274,7 @@ protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInf if (!genericType.IsAssignableFrom(typeof(TSource))) throw new InvalidOperationException($"Invalid {nameof(IResolveFieldContext)}<> type for method {method.Name}"); //convert the IResolveFieldContext to the specified ResolveFieldContext<> - var asMethodTyped = asMethod.MakeGenericMethod(genericType); + var asMethodTyped = _asMethod.MakeGenericMethod(genericType); //e.g. Func> = (context) => context.As(); expr = Expression.Call(asMethodTyped, resolveFieldContextParameter); //and do not add it as a QueryArgument @@ -277,7 +286,7 @@ protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInf throw new InvalidOperationException($"Invalid {nameof(IResolveFieldContext)}<> type for method {method.Name}"); //retrieve the value and cast it to the specified type //e.g. Func = (context) => (TSource)context.Source; - expr = Expression.Convert(Expression.Property(resolveFieldContextParameter, sourceProperty), param.ParameterType); + expr = Expression.Convert(Expression.Property(resolveFieldContextParameter, _sourceProperty), param.ParameterType); //and do not add it as a QueryArgument return null; } @@ -348,7 +357,7 @@ protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInf } //construct a call to ResolveFieldContextExtensions.GetArgument, passing in the appropriate default value - var getArgumentMethodTyped = getArgumentMethod.MakeGenericMethod(param.ParameterType); + var getArgumentMethodTyped = _getArgumentMethod.MakeGenericMethod(param.ParameterType); //e.g. Func = (context) => ResolveFieldContextExtensions.GetArgument(context, argument.Name, defaultValue); expr = Expression.Call(getArgumentMethodTyped, resolveFieldContextParameter, Expression.Constant(argument.Name), Expression.Constant(defaultValue, param.ParameterType)); diff --git a/src/ResolveFieldContextAdapter.cs b/src/ResolveFieldContextAdapter.cs deleted file mode 100644 index e3041da..0000000 --- a/src/ResolveFieldContextAdapter.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using GraphQL.Instrumentation; -using GraphQL.Language.AST; -using GraphQL.Types; - -namespace GraphQL.DI -{ - public class ResolveFieldContextAdapter : IResolveFieldContext - { - private readonly IResolveFieldContext _baseContext; - - public ResolveFieldContextAdapter(IResolveFieldContext baseContext) - { - _baseContext = baseContext ?? throw new ArgumentNullException(nameof(baseContext)); - - try { - Source = (T)baseContext.Source; - } catch (InvalidCastException) { - throw new ArgumentException("baseContext.Source is not of type " + typeof(T).Name, nameof(baseContext)); - } catch (NullReferenceException) { - throw new ArgumentException("baseContext.Source is null and cannot be cast to non-nullable value type " + typeof(T).Name, nameof(baseContext)); - } - } - - public T Source { get; } - - public string FieldName => _baseContext.FieldName; - - public Language.AST.Field FieldAst => _baseContext.FieldAst; - - public FieldType FieldDefinition => _baseContext.FieldDefinition; - - public IGraphType ReturnType => _baseContext.ReturnType; - - public IObjectGraphType ParentType => _baseContext.ParentType; - - public IDictionary Arguments => _baseContext.Arguments; - - public object RootValue => _baseContext.RootValue; - - public ISchema Schema => _baseContext.Schema; - - public Document Document => _baseContext.Document; - - public Operation Operation => _baseContext.Operation; - - public Fragments Fragments => _baseContext.Fragments; - - public Variables Variables => _baseContext.Variables; - - public CancellationToken CancellationToken => _baseContext.CancellationToken; - - public Metrics Metrics => _baseContext.Metrics; - - public ExecutionErrors Errors => _baseContext.Errors; - - public IEnumerable Path => _baseContext.Path; - - public IDictionary Extensions => _baseContext.Extensions; - - public IDictionary SubFields => _baseContext.SubFields; - - public IDictionary UserContext => _baseContext.UserContext; - - public IEnumerable ResponsePath => _baseContext.ResponsePath; - - public IServiceProvider RequestServices => _baseContext.RequestServices; - - object IResolveFieldContext.Source => Source; - } -} diff --git a/src/ResolveFieldContextExtensions.cs b/src/ResolveFieldContextExtensions.cs deleted file mode 100644 index 899595a..0000000 --- a/src/ResolveFieldContextExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace GraphQL.DI -{ - public static class ResolveFieldContextExtensions - { - public static IResolveFieldContext As(this IResolveFieldContext context) - { - if (context is IResolveFieldContext typedContext) - return typedContext; - - return new ResolveFieldContextAdapter(context); - } - } -} diff --git a/src/ScopedFieldResolver.cs b/src/ScopedFieldResolver.cs deleted file mode 100644 index b98bfd7..0000000 --- a/src/ScopedFieldResolver.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Threading.Tasks; -using GraphQL.Resolvers; -using Microsoft.Extensions.DependencyInjection; - -namespace GraphQL.DI -{ - public class DIScopedFieldResolver : AsyncFieldResolver - { - public DIScopedFieldResolver(Func> resolver) : base(ScopeResolver(resolver)) { } - - private static Func> ScopeResolver(Func> resolver) - { - return async (context) => { - var serviceProvider = context.RequestServices ?? throw new InvalidOperationException("No service provider defined in this context"); - using (var newScope = serviceProvider.CreateScope()) { - context = new ContextWrapper(context, newScope.ServiceProvider); - var ret = resolver(context); - return await ret.ConfigureAwait(false); - } - }; - } - } - - public class DIScopedFieldResolver : AsyncFieldResolver - { - public DIScopedFieldResolver(Func, Task> resolver) : base(ScopeResolver(resolver)) { } - - private static Func, Task> ScopeResolver(Func, Task> resolver) - { - return async (context) => { - var serviceProvider = context.RequestServices ?? throw new InvalidOperationException("No service provider defined in this context"); - using (var newScope = serviceProvider.CreateScope()) { - context = new ContextWrapper(context, newScope.ServiceProvider); - var ret = resolver(context); - return await ret.ConfigureAwait(false); - } - }; - } - } -} diff --git a/src/Shane32.GraphQL.DI.csproj b/src/Shane32.GraphQL.DI.csproj index ffd4bf2..7d35e93 100644 --- a/src/Shane32.GraphQL.DI.csproj +++ b/src/Shane32.GraphQL.DI.csproj @@ -5,7 +5,8 @@ - + + From fa72ec6ba1dfe48f987d15e8811a3d41ab09472e Mon Sep 17 00:00:00 2001 From: Shane32 Date: Mon, 22 Mar 2021 00:50:51 -0400 Subject: [PATCH 02/31] Add some tests --- GraphQL.DI.sln | 6 + Tests/DIObjectGraphType.cs | 308 +++++++++++++++++++++++++++++++++++++ Tests/Extensions.cs | 12 ++ Tests/Tests.csproj | 32 ++++ src/DIObjectGraphType.cs | 10 +- 5 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 Tests/DIObjectGraphType.cs create mode 100644 Tests/Extensions.cs create mode 100644 Tests/Tests.csproj diff --git a/GraphQL.DI.sln b/GraphQL.DI.sln index f4486bc..eea3ce7 100644 --- a/GraphQL.DI.sln +++ b/GraphQL.DI.sln @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{BA5F3790-9FE0-4A10-8528-0756334AC727}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}.Debug|Any CPU.Build.0 = Debug|Any CPU {72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}.Release|Any CPU.ActiveCfg = Release|Any CPU {72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}.Release|Any CPU.Build.0 = Release|Any CPU + {BA5F3790-9FE0-4A10-8528-0756334AC727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA5F3790-9FE0-4A10-8528-0756334AC727}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA5F3790-9FE0-4A10-8528-0756334AC727}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA5F3790-9FE0-4A10-8528-0756334AC727}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tests/DIObjectGraphType.cs b/Tests/DIObjectGraphType.cs new file mode 100644 index 0000000..2b1d494 --- /dev/null +++ b/Tests/DIObjectGraphType.cs @@ -0,0 +1,308 @@ +using System; +using Xunit; +using Shouldly; +using GraphQL.DI; +using GraphQL.Types; +using System.ComponentModel; +using Moq; +using GraphQL; +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; + +namespace Tests +{ + public class DIObjectGraphType + { + private object _source; + private ObjectGraphType _graphType; + private readonly Mock _scopedServiceProviderMock; + private readonly Mock _scopeMock; + private readonly Mock _scopeFactoryMock; + private readonly Mock _serviceProviderMock; + private readonly Mock _contextMock; + + public DIObjectGraphType() : base() + { + _scopedServiceProviderMock = new Mock(MockBehavior.Strict); + _scopeMock = new Mock(MockBehavior.Strict); + _scopeMock.Setup(x => x.Dispose()); + _scopeMock.SetupGet(x => x.ServiceProvider).Returns(_scopedServiceProviderMock.Object); + _scopeFactoryMock = new Mock(MockBehavior.Strict); + _scopeFactoryMock.Setup(x => x.CreateScope()).Returns(_scopeMock.Object); + _serviceProviderMock = new Mock(MockBehavior.Strict); + _serviceProviderMock.Setup(x => x.GetService(typeof(IServiceScopeFactory))).Returns(_scopeFactoryMock.Object); + _contextMock = new Mock(MockBehavior.Strict); + _contextMock.SetupGet(x => x.RequestServices).Returns(_serviceProviderMock.Object); + _contextMock.SetupGet(x => x.Source).Returns(() => _source); + } + + private ObjectGraphType Configure(bool instance = false, bool scoped = false) where T : DIObjectGraphBase, new() + { + if (instance) { + if (scoped) { + _scopedServiceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); + } else { + _serviceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); + } + } + _graphType = new DIObjectGraphType(); + return _graphType; + } + + private FieldType VerifyField(string fieldName, bool nullable, bool concurrent, T returnValue) + { + var context = _contextMock.Object; + _graphType.ShouldNotBeNull(); + _graphType.Fields.ShouldNotBeNull(); + var field = _graphType.Fields.Find(fieldName); + field.ShouldNotBeNull(); + field.Type.ShouldBe(nullable ? typeof(GraphQLClrOutputTypeReference) : typeof(NonNullGraphType>)); + field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); + field.Resolver.ShouldNotBeNull(); + field.Resolver.Resolve(context).ShouldBe(returnValue); + return field; + } + + private async Task VerifyFieldAsync(string fieldName, bool nullable, bool concurrent, T returnValue) + { + var context = _contextMock.Object; + _graphType.ShouldNotBeNull(); + _graphType.Fields.ShouldNotBeNull(); + var field = _graphType.Fields.Find(fieldName); + field.ShouldNotBeNull(); + field.Type.ShouldBe(nullable ? typeof(GraphQLClrOutputTypeReference) : typeof(NonNullGraphType>)); + field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); + field.Resolver.ShouldNotBeNull(); + var ret = field.Resolver.Resolve(context); + var taskRet = ret.ShouldBeOfType>(); + var final = await taskRet; + final.ShouldBe(returnValue); + return field; + } + + private void Verify(bool scoped) + { + if (scoped) { + _contextMock.Verify(x => x.RequestServices, Times.Once); + _serviceProviderMock.Verify(x => x.GetService(typeof(IServiceScopeFactory)), Times.Once); + _scopeFactoryMock.Verify(x => x.CreateScope(), Times.Once); + _scopeMock.Verify(x => x.ServiceProvider, Times.Once); + } + else { + _contextMock.Verify(x => x.RequestServices, Times.Between(0, 100, Moq.Range.Inclusive)); + } + _contextMock.Verify(); + _serviceProviderMock.Verify(); + _scopeMock.Verify(); + _scopeFactoryMock.Verify(); + _scopedServiceProviderMock.Verify(); + _contextMock.VerifyNoOtherCalls(); + _serviceProviderMock.VerifyNoOtherCalls(); + _scopeMock.VerifyNoOtherCalls(); + _scopeFactoryMock.VerifyNoOtherCalls(); + _scopedServiceProviderMock.VerifyNoOtherCalls(); + } + + [Fact] + public void GraphName() + { + Configure().Name.ShouldBe("TestGraphName"); + } + + [Name("TestGraphName")] + public class CGraphName : DIObjectGraphBase { } + + [Fact] + public void GraphDescription() + { + Configure().Description.ShouldBe("TestGraphDescription"); + } + + [Description("TestGraphDescription")] + public class CGraphDescription : DIObjectGraphBase { } + + [Fact] + public void GraphObsolete() + { + Configure().DeprecationReason.ShouldBe("TestDeprecationReason"); + } + + [Obsolete("TestDeprecationReason")] + public class CGraphObsolete : DIObjectGraphBase { } + + [Fact] + public void GraphMetadata() + { + Configure().GetMetadata("test").ShouldBe("value"); + } + + [Metadata("test", "value")] + public class CGraphMetadata : DIObjectGraphBase { } + + [Fact] + public void FieldStaticMethod() + { + Configure(); + VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CFieldStaticMethod : DIObjectGraphBase + { + public CFieldStaticMethod() => throw new Exception(); + + public static string Field1() => "hello"; + } + + [Fact] + public void FieldInstanceMethod() + { + Configure(true); + VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CFieldInstanceMethod : DIObjectGraphBase + { + public string Field1() => "hello"; + } + + [Fact] + public async Task FieldStaticAsyncMethod() + { + Configure(); + await VerifyFieldAsync("Field1", nullable: true, concurrent: true, returnValue: "hello"); + Verify(false); + } + + public class CFieldStaticAsyncMethod : DIObjectGraphBase + { + public CFieldStaticAsyncMethod() => throw new Exception(); + + public static Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public async Task FieldInstanceAsyncMethod() + { + Configure(true); + await VerifyFieldAsync("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CFieldInstanceAsyncMethod : DIObjectGraphBase + { + public Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public void FieldName() + { + Configure(); + VerifyField("FieldTest", true, false, "hello"); + Verify(false); + } + + public class CFieldName : DIObjectGraphBase + { + [Name("FieldTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void FieldDescription() + { + Configure(); + VerifyField("Field1", true, false, "hello").Description.ShouldBe("DescriptionTest"); + Verify(false); + } + + public class CFieldDescription : DIObjectGraphBase + { + [Description("DescriptionTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void FieldObsolete() + { + Configure(); + VerifyField("Field1", true, false, "hello").DeprecationReason.ShouldBe("ObsoleteTest"); + Verify(false); + } + + public class CFieldObsolete : DIObjectGraphBase + { + [Obsolete("ObsoleteTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void FieldContext() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.Once); + Verify(false); + } + + public class CFieldContext : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => (string)context.Source; + } + + [Fact] + public void FieldContext_Typed() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.AtLeastOnce); + Verify(false); + } + + public class CFieldContext_Typed : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => (string)context.Source; + } + + [Fact] + public void FieldContext_WrongType() + { + Should.Throw(() => Configure()); + } + + public class CFieldContext_WrongType : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => context.Source; + } + + [Fact] + public void FieldSource() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.Once); + Verify(false); + } + + public class CFieldSource : DIObjectGraphBase + { + public static string Field1([FromSource] object source) => (string)source; + } + + [Fact] + public void FieldSource_WrongType() + { + Should.Throw(() => Configure()); + } + + public class CFieldSource_WrongType : DIObjectGraphBase + { + public static string Field1([FromSource] string source) => source; + } + + } +} diff --git a/Tests/Extensions.cs b/Tests/Extensions.cs new file mode 100644 index 0000000..706a145 --- /dev/null +++ b/Tests/Extensions.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using GraphQL.Types; +using Shouldly; + +namespace Tests +{ + public static class Extensions + { + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 0000000..4fb0aec --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.1 + + false + + + + 1701;1702;1591 + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index 163d1e8..3bddfc4 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -44,7 +44,7 @@ public DIObjectGraphType() //grab some methods via reflection for us to use later private static readonly MethodInfo _getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(ServiceProviderServiceExtensions.GetRequiredService) && !x.IsGenericMethod); - private static readonly MethodInfo _asMethod = typeof(ResolveFieldContextExtensions).GetMethod(nameof(ResolveFieldContextExtensions.As), BindingFlags.Static | BindingFlags.Public); + private static readonly MethodInfo _asMethod = typeof(ResolveFieldContextExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Single(x => x.Name == nameof(ResolveFieldContextExtensions.As) && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(IResolveFieldContext)); private static readonly MethodInfo _getArgumentMethod = typeof(ResolveFieldContextExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Single(x => x.Name == nameof(ResolveFieldContextExtensions.GetArgument) && x.IsGenericMethod); private static readonly PropertyInfo _sourceProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.Source), BindingFlags.Instance | BindingFlags.Public); private static readonly PropertyInfo _requestServicesProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.RequestServices), BindingFlags.Instance | BindingFlags.Public); @@ -65,7 +65,7 @@ protected virtual List CreateFieldTypeList() protected virtual IEnumerable GetMethodsToProcess() { - return typeof(TDIGraph).GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | BindingFlags.DeclaredOnly); + return typeof(TDIGraph).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); } protected virtual DIFieldType ProcessMethod(MethodInfo method) @@ -216,7 +216,11 @@ protected virtual Expression GetServiceProviderExpression(ParameterExpression re protected virtual Expression GetServiceExpression(ParameterExpression resolveFieldContextParameter, Type serviceType) { //returns: (serviceType)(context.RequestServices.GetRequiredService(serviceType)) - return Expression.Convert(Expression.Call(_getRequiredServiceMethod, GetServiceProviderExpression(resolveFieldContextParameter), Expression.Constant(serviceType)), serviceType); + var serviceProvider = GetServiceProviderExpression(resolveFieldContextParameter); + var type = Expression.Constant(serviceType ?? throw new ArgumentNullException(nameof(serviceType))); + var getService = Expression.Call(_getRequiredServiceMethod, serviceProvider, type); + var cast = Expression.Convert(getService, serviceType); + return cast; } private ConcurrentDictionary _funcFieldResolverConstructors = new ConcurrentDictionary(); From c08dd1b325fc1d2bb269b5fae27afc1d93c8df90 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Mon, 22 Mar 2021 14:44:00 -0400 Subject: [PATCH 03/31] Add more tests --- Tests/DIObjectGraphType.cs | 308 -------------- Tests/DIObjectGraphTypeTests/Argument.cs | 111 ++++++ .../DIObjectGraphTypeTestBase.cs | 130 ++++++ Tests/DIObjectGraphTypeTests/Field.cs | 376 ++++++++++++++++++ Tests/DIObjectGraphTypeTests/Graph.cs | 47 +++ Tests/DIObjectGraphTypeTests/Services.cs | 51 +++ Tests/Tests.csproj | 1 + src/ConcurrentAttribute.cs | 3 +- src/DIObjectGraphType.cs | 53 ++- 9 files changed, 754 insertions(+), 326 deletions(-) delete mode 100644 Tests/DIObjectGraphType.cs create mode 100644 Tests/DIObjectGraphTypeTests/Argument.cs create mode 100644 Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs create mode 100644 Tests/DIObjectGraphTypeTests/Field.cs create mode 100644 Tests/DIObjectGraphTypeTests/Graph.cs create mode 100644 Tests/DIObjectGraphTypeTests/Services.cs diff --git a/Tests/DIObjectGraphType.cs b/Tests/DIObjectGraphType.cs deleted file mode 100644 index 2b1d494..0000000 --- a/Tests/DIObjectGraphType.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System; -using Xunit; -using Shouldly; -using GraphQL.DI; -using GraphQL.Types; -using System.ComponentModel; -using Moq; -using GraphQL; -using Microsoft.Extensions.DependencyInjection; -using System.Threading.Tasks; - -namespace Tests -{ - public class DIObjectGraphType - { - private object _source; - private ObjectGraphType _graphType; - private readonly Mock _scopedServiceProviderMock; - private readonly Mock _scopeMock; - private readonly Mock _scopeFactoryMock; - private readonly Mock _serviceProviderMock; - private readonly Mock _contextMock; - - public DIObjectGraphType() : base() - { - _scopedServiceProviderMock = new Mock(MockBehavior.Strict); - _scopeMock = new Mock(MockBehavior.Strict); - _scopeMock.Setup(x => x.Dispose()); - _scopeMock.SetupGet(x => x.ServiceProvider).Returns(_scopedServiceProviderMock.Object); - _scopeFactoryMock = new Mock(MockBehavior.Strict); - _scopeFactoryMock.Setup(x => x.CreateScope()).Returns(_scopeMock.Object); - _serviceProviderMock = new Mock(MockBehavior.Strict); - _serviceProviderMock.Setup(x => x.GetService(typeof(IServiceScopeFactory))).Returns(_scopeFactoryMock.Object); - _contextMock = new Mock(MockBehavior.Strict); - _contextMock.SetupGet(x => x.RequestServices).Returns(_serviceProviderMock.Object); - _contextMock.SetupGet(x => x.Source).Returns(() => _source); - } - - private ObjectGraphType Configure(bool instance = false, bool scoped = false) where T : DIObjectGraphBase, new() - { - if (instance) { - if (scoped) { - _scopedServiceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); - } else { - _serviceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); - } - } - _graphType = new DIObjectGraphType(); - return _graphType; - } - - private FieldType VerifyField(string fieldName, bool nullable, bool concurrent, T returnValue) - { - var context = _contextMock.Object; - _graphType.ShouldNotBeNull(); - _graphType.Fields.ShouldNotBeNull(); - var field = _graphType.Fields.Find(fieldName); - field.ShouldNotBeNull(); - field.Type.ShouldBe(nullable ? typeof(GraphQLClrOutputTypeReference) : typeof(NonNullGraphType>)); - field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); - field.Resolver.ShouldNotBeNull(); - field.Resolver.Resolve(context).ShouldBe(returnValue); - return field; - } - - private async Task VerifyFieldAsync(string fieldName, bool nullable, bool concurrent, T returnValue) - { - var context = _contextMock.Object; - _graphType.ShouldNotBeNull(); - _graphType.Fields.ShouldNotBeNull(); - var field = _graphType.Fields.Find(fieldName); - field.ShouldNotBeNull(); - field.Type.ShouldBe(nullable ? typeof(GraphQLClrOutputTypeReference) : typeof(NonNullGraphType>)); - field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); - field.Resolver.ShouldNotBeNull(); - var ret = field.Resolver.Resolve(context); - var taskRet = ret.ShouldBeOfType>(); - var final = await taskRet; - final.ShouldBe(returnValue); - return field; - } - - private void Verify(bool scoped) - { - if (scoped) { - _contextMock.Verify(x => x.RequestServices, Times.Once); - _serviceProviderMock.Verify(x => x.GetService(typeof(IServiceScopeFactory)), Times.Once); - _scopeFactoryMock.Verify(x => x.CreateScope(), Times.Once); - _scopeMock.Verify(x => x.ServiceProvider, Times.Once); - } - else { - _contextMock.Verify(x => x.RequestServices, Times.Between(0, 100, Moq.Range.Inclusive)); - } - _contextMock.Verify(); - _serviceProviderMock.Verify(); - _scopeMock.Verify(); - _scopeFactoryMock.Verify(); - _scopedServiceProviderMock.Verify(); - _contextMock.VerifyNoOtherCalls(); - _serviceProviderMock.VerifyNoOtherCalls(); - _scopeMock.VerifyNoOtherCalls(); - _scopeFactoryMock.VerifyNoOtherCalls(); - _scopedServiceProviderMock.VerifyNoOtherCalls(); - } - - [Fact] - public void GraphName() - { - Configure().Name.ShouldBe("TestGraphName"); - } - - [Name("TestGraphName")] - public class CGraphName : DIObjectGraphBase { } - - [Fact] - public void GraphDescription() - { - Configure().Description.ShouldBe("TestGraphDescription"); - } - - [Description("TestGraphDescription")] - public class CGraphDescription : DIObjectGraphBase { } - - [Fact] - public void GraphObsolete() - { - Configure().DeprecationReason.ShouldBe("TestDeprecationReason"); - } - - [Obsolete("TestDeprecationReason")] - public class CGraphObsolete : DIObjectGraphBase { } - - [Fact] - public void GraphMetadata() - { - Configure().GetMetadata("test").ShouldBe("value"); - } - - [Metadata("test", "value")] - public class CGraphMetadata : DIObjectGraphBase { } - - [Fact] - public void FieldStaticMethod() - { - Configure(); - VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); - Verify(false); - } - - public class CFieldStaticMethod : DIObjectGraphBase - { - public CFieldStaticMethod() => throw new Exception(); - - public static string Field1() => "hello"; - } - - [Fact] - public void FieldInstanceMethod() - { - Configure(true); - VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); - Verify(false); - } - - public class CFieldInstanceMethod : DIObjectGraphBase - { - public string Field1() => "hello"; - } - - [Fact] - public async Task FieldStaticAsyncMethod() - { - Configure(); - await VerifyFieldAsync("Field1", nullable: true, concurrent: true, returnValue: "hello"); - Verify(false); - } - - public class CFieldStaticAsyncMethod : DIObjectGraphBase - { - public CFieldStaticAsyncMethod() => throw new Exception(); - - public static Task Field1() => Task.FromResult("hello"); - } - - [Fact] - public async Task FieldInstanceAsyncMethod() - { - Configure(true); - await VerifyFieldAsync("Field1", nullable: true, concurrent: false, returnValue: "hello"); - Verify(false); - } - - public class CFieldInstanceAsyncMethod : DIObjectGraphBase - { - public Task Field1() => Task.FromResult("hello"); - } - - [Fact] - public void FieldName() - { - Configure(); - VerifyField("FieldTest", true, false, "hello"); - Verify(false); - } - - public class CFieldName : DIObjectGraphBase - { - [Name("FieldTest")] - public static string Field1() => "hello"; - } - - [Fact] - public void FieldDescription() - { - Configure(); - VerifyField("Field1", true, false, "hello").Description.ShouldBe("DescriptionTest"); - Verify(false); - } - - public class CFieldDescription : DIObjectGraphBase - { - [Description("DescriptionTest")] - public static string Field1() => "hello"; - } - - [Fact] - public void FieldObsolete() - { - Configure(); - VerifyField("Field1", true, false, "hello").DeprecationReason.ShouldBe("ObsoleteTest"); - Verify(false); - } - - public class CFieldObsolete : DIObjectGraphBase - { - [Obsolete("ObsoleteTest")] - public static string Field1() => "hello"; - } - - [Fact] - public void FieldContext() - { - Configure(); - _source = "testSource"; - VerifyField("Field1", true, false, "testSource"); - _contextMock.Verify(x => x.Source, Times.Once); - Verify(false); - } - - public class CFieldContext : DIObjectGraphBase - { - public static string Field1(IResolveFieldContext context) => (string)context.Source; - } - - [Fact] - public void FieldContext_Typed() - { - Configure(); - _source = "testSource"; - VerifyField("Field1", true, false, "testSource"); - _contextMock.Verify(x => x.Source, Times.AtLeastOnce); - Verify(false); - } - - public class CFieldContext_Typed : DIObjectGraphBase - { - public static string Field1(IResolveFieldContext context) => (string)context.Source; - } - - [Fact] - public void FieldContext_WrongType() - { - Should.Throw(() => Configure()); - } - - public class CFieldContext_WrongType : DIObjectGraphBase - { - public static string Field1(IResolveFieldContext context) => context.Source; - } - - [Fact] - public void FieldSource() - { - Configure(); - _source = "testSource"; - VerifyField("Field1", true, false, "testSource"); - _contextMock.Verify(x => x.Source, Times.Once); - Verify(false); - } - - public class CFieldSource : DIObjectGraphBase - { - public static string Field1([FromSource] object source) => (string)source; - } - - [Fact] - public void FieldSource_WrongType() - { - Should.Throw(() => Configure()); - } - - public class CFieldSource_WrongType : DIObjectGraphBase - { - public static string Field1([FromSource] string source) => source; - } - - } -} diff --git a/Tests/DIObjectGraphTypeTests/Argument.cs b/Tests/DIObjectGraphTypeTests/Argument.cs new file mode 100644 index 0000000..34876c0 --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/Argument.cs @@ -0,0 +1,111 @@ +using System.ComponentModel; +using GraphQL.DI; +using GraphQL.Types; +using Shouldly; +using Xunit; + +namespace DIObjectGraphTypeTests +{ + public class Argument : DIObjectGraphTypeTestBase + { + [Fact] + public void NonNullValue() + { + Configure(); + VerifyFieldArgument("Field1", "arg", false, 2); + VerifyField("Field1", false, false, 2); + Verify(false); + } + + public class CNonNullValue : DIObjectGraphBase + { + public static int Field1(int arg) => arg; + } + + [Fact] + public void NullableValue() + { + Configure(); + VerifyFieldArgument("Field1", "arg", true, (int?)2); + VerifyField("Field1", true, false, 2); + Verify(false); + } + + public class CNullableValue : DIObjectGraphBase + { + public static int? Field1(int? arg) => arg; + } + + [Fact] + public void NullableObject() + { + Configure(); + VerifyFieldArgument("Field1", "arg", true, "hello"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CNullableObject : DIObjectGraphBase + { + public static string Field1(string arg) => arg; + } + + [Fact] + public void NonNullableObject() + { + Configure(); + VerifyFieldArgument("Field1", "arg", false, "hello"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CNonNullableObject : DIObjectGraphBase + { + public static string Field1([Required] string arg) => arg; + } + + [Fact] + public void Name() + { + Configure(); + VerifyFieldArgument("Field1", "AltName", true, "hello"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CName : DIObjectGraphBase + { + public static string Field1([Name("AltName")] string arg) => arg; + } + + [Fact] + public void Description() + { + Configure(); + var arg = VerifyFieldArgument("Field1", "arg", true, "hello"); + arg.Description.ShouldBe("TestDescription"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CDescription : DIObjectGraphBase + { + public static string Field1([Description("TestDescription")] string arg) => arg; + } + + [Fact] + public void GraphType() + { + Configure(); + VerifyFieldArgument("Field1", "arg", typeof(StringGraphType), "hello"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CGraphType : DIObjectGraphBase + { + public static string Field1([GraphType(typeof(StringGraphType))] string arg) => arg; + } + + } +} diff --git a/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs b/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs new file mode 100644 index 0000000..edf6d98 --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using GraphQL; +using GraphQL.DI; +using GraphQL.Execution; +using GraphQL.Types; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Shouldly; + +namespace DIObjectGraphTypeTests +{ + public class DIObjectGraphTypeTestBase + { + protected object _source; + protected IComplexGraphType _graphType; + protected readonly Mock _scopedServiceProviderMock; + protected readonly Mock _scopeMock; + protected readonly Mock _scopeFactoryMock; + protected readonly Mock _serviceProviderMock; + protected readonly Mock _contextMock; + protected readonly Dictionary _arguments = new(); + + public DIObjectGraphTypeTestBase() : base() + { + _scopedServiceProviderMock = new Mock(MockBehavior.Strict); + _scopeMock = new Mock(MockBehavior.Strict); + _scopeMock.Setup(x => x.Dispose()); + _scopeMock.SetupGet(x => x.ServiceProvider).Returns(_scopedServiceProviderMock.Object); + _scopeFactoryMock = new Mock(MockBehavior.Strict); + _scopeFactoryMock.Setup(x => x.CreateScope()).Returns(_scopeMock.Object); + _serviceProviderMock = new Mock(MockBehavior.Strict); + _serviceProviderMock.Setup(x => x.GetService(typeof(IServiceScopeFactory))).Returns(_scopeFactoryMock.Object); + _contextMock = new Mock(MockBehavior.Strict); + _contextMock.SetupGet(x => x.RequestServices).Returns(_serviceProviderMock.Object); + _contextMock.SetupGet(x => x.Source).Returns(() => _source); + _contextMock.SetupGet(x => x.ParentType).Returns(new ObjectGraphType()); + _contextMock.SetupGet(x => x.Arguments).Returns(() => _arguments); + _contextMock.SetupGet(x => x.Schema).Returns((ISchema)null); + } + + protected IComplexGraphType Configure(bool instance = false, bool scoped = false) where T : DIObjectGraphBase, new() + { + if (instance) { + if (scoped) { + _scopedServiceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); + } else { + _serviceProviderMock.Setup(x => x.GetService(typeof(T))).Returns(() => new T()).Verifiable(); + } + } + _graphType = new DIObjectGraphType(); + return _graphType; + } + + protected FieldType VerifyField(string fieldName, bool nullable, bool concurrent, T returnValue) + { + return VerifyField(fieldName, typeof(T).GetGraphTypeFromType(nullable, TypeMappingMode.OutputType), concurrent, returnValue); + } + + protected FieldType VerifyField(string fieldName, Type fieldGraphType, bool concurrent, T returnValue) + { + var context = _contextMock.Object; + _graphType.ShouldNotBeNull(); + _graphType.Fields.ShouldNotBeNull(); + var field = _graphType.Fields.Find(fieldName); + field.ShouldNotBeNull(); + field.Type.ShouldBe(fieldGraphType); + field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); + field.Resolver.ShouldNotBeNull(); + _contextMock.Setup(x => x.FieldDefinition).Returns(field); + field.Resolver.Resolve(context).ShouldBe(returnValue); + return field; + } + + protected async Task VerifyFieldAsync(string fieldName, bool nullable, bool concurrent, T returnValue) + { + var context = _contextMock.Object; + _graphType.ShouldNotBeNull(); + _graphType.Fields.ShouldNotBeNull(); + var field = _graphType.Fields.Find(fieldName); + field.ShouldNotBeNull(); + field.Type.ShouldBe(typeof(T).GetGraphTypeFromType(nullable, TypeMappingMode.OutputType)); + field.ShouldBeOfType().Concurrent.ShouldBe(concurrent); + field.Resolver.ShouldNotBeNull(); + _contextMock.Setup(x => x.FieldDefinition).Returns(field); + var ret = field.Resolver.Resolve(context); + var taskRet = ret.ShouldBeOfType>(); + var final = await taskRet; + final.ShouldBe(returnValue); + return field; + } + + protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, bool nullable, T returnValue) + { + return VerifyFieldArgument(fieldName, argumentName, typeof(T).GetGraphTypeFromType(nullable, TypeMappingMode.InputType), returnValue); + } + + protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, Type graphType, T returnValue) + { + _graphType.ShouldNotBeNull(); + _graphType.Fields.ShouldNotBeNull(); + var field = _graphType.Fields.Find(fieldName); + field.ShouldNotBeNull(); + field.Arguments.ShouldNotBeNull(); + var argument = field.Arguments.Find(argumentName); + argument.ShouldNotBeNull(); + argument.Type.ShouldBe(graphType); + _arguments.Add(argumentName, new ArgumentValue(returnValue, ArgumentSource.FieldDefault)); + return argument; + } + + protected void Verify(bool scoped) + { + if (scoped) { + _contextMock.Verify(x => x.RequestServices, Times.Once); + _serviceProviderMock.Verify(x => x.GetService(typeof(IServiceScopeFactory)), Times.Once); + _scopeFactoryMock.Verify(x => x.CreateScope(), Times.Once); + _scopeMock.Verify(x => x.ServiceProvider, Times.Once); + } else { + _serviceProviderMock.Verify(x => x.GetService(typeof(IServiceScopeFactory)), Times.Never); + } + _contextMock.Verify(); + _serviceProviderMock.Verify(); + _scopeMock.Verify(); + _scopeFactoryMock.Verify(); + _scopedServiceProviderMock.Verify(); + } + } +} diff --git a/Tests/DIObjectGraphTypeTests/Field.cs b/Tests/DIObjectGraphTypeTests/Field.cs new file mode 100644 index 0000000..ab374cc --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/Field.cs @@ -0,0 +1,376 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using GraphQL; +using GraphQL.DI; +using GraphQL.Types; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Shouldly; +using Xunit; + +namespace DIObjectGraphTypeTests +{ + public class Field : DIObjectGraphTypeTestBase + { + [Fact] + public void StaticMethod() + { + Configure(); + VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CStaticMethod : DIObjectGraphBase + { + public CStaticMethod() => throw new Exception(); + + public static string Field1() => "hello"; + } + + [Fact] + public void InstanceMethod() + { + Configure(true); + VerifyField("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CInstanceMethod : DIObjectGraphBase + { + public string Field1() => "hello"; + } + + [Fact] + public async Task StaticAsyncMethod() + { + Configure(); + await VerifyFieldAsync("Field1", nullable: true, concurrent: true, returnValue: "hello"); + Verify(false); + } + + public class CStaticAsyncMethod : DIObjectGraphBase + { + public CStaticAsyncMethod() => throw new Exception(); + + public static Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public async Task InstanceAsyncMethod() + { + Configure(true); + await VerifyFieldAsync("Field1", nullable: true, concurrent: false, returnValue: "hello"); + Verify(false); + } + + public class CInstanceAsyncMethod : DIObjectGraphBase + { + public Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public void Name() + { + Configure(); + VerifyField("FieldTest", true, false, "hello"); + Verify(false); + } + + public class CName : DIObjectGraphBase + { + [Name("FieldTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void Description() + { + Configure(); + VerifyField("Field1", true, false, "hello").Description.ShouldBe("DescriptionTest"); + Verify(false); + } + + public class CDescription : DIObjectGraphBase + { + [Description("DescriptionTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void Obsolete() + { + Configure(); + VerifyField("Field1", true, false, "hello").DeprecationReason.ShouldBe("ObsoleteTest"); + Verify(false); + } + + public class CObsolete : DIObjectGraphBase + { + [Obsolete("ObsoleteTest")] + public static string Field1() => "hello"; + } + + [Fact] + public void Context() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.Once); + Verify(false); + } + + public class CContext : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => (string)context.Source; + } + + [Fact] + public void Context_Typed() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.AtLeastOnce); + Verify(false); + } + + public class CContext_Typed : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => (string)context.Source; + } + + [Fact] + public void Context_WrongType() + { + Should.Throw(() => Configure()); + } + + public class CContext_WrongType : DIObjectGraphBase + { + public static string Field1(IResolveFieldContext context) => context.Source; + } + + [Fact] + public void Source() + { + Configure(); + _source = "testSource"; + VerifyField("Field1", true, false, "testSource"); + _contextMock.Verify(x => x.Source, Times.Once); + Verify(false); + } + + public class CSource : DIObjectGraphBase + { + public static string Field1([FromSource] object source) => (string)source; + } + + [Fact] + public void Source_WrongType() + { + Should.Throw(() => Configure()); + } + + public class CSource_WrongType : DIObjectGraphBase + { + public static string Field1([FromSource] string source) => source; + } + + [Fact] + public void ServiceProvider() + { + Configure(); + _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns("hello").Verifiable(); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CServiceProvider : DIObjectGraphBase + { + public static string Field1(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService(); + } + + [Fact] + public async Task ServiceProviderForScoped() + { + Configure(); + _scopedServiceProviderMock.Setup(x => x.GetService(typeof(string))).Returns("hello").Verifiable(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(true); + } + + public class CServiceProviderForScoped : DIObjectGraphBase + { + [Concurrent(true)] + public static Task Field1(IServiceProvider serviceProvider) => Task.FromResult(serviceProvider.GetRequiredService()); + } + + [Fact] + public void NullableValue() + { + Configure(); + VerifyField("Field1", true, false, (int?)null); + Verify(false); + } + + public class CNullableValue : DIObjectGraphBase + { + public static int? Field1() => null; + } + + [Fact] + public void NonNullableValue() + { + Configure(); + VerifyField("Field1", false, false, 1); + Verify(false); + } + + public class CNonNullableValue : DIObjectGraphBase + { + public static int Field1() => 1; + } + + [Fact] + public void Required() + { + Configure(); + VerifyField("Field1", false, false, "hello"); + Verify(false); + } + + public class CRequired : DIObjectGraphBase + { + [Required] + public static string Field1() => "hello"; + } + + [Fact] + public void CustomType() + { + Configure(); + VerifyField("Field1", typeof(StringGraphType), false, "hello"); + Verify(false); + } + + public class CCustomType : DIObjectGraphBase + { + [GraphType(typeof(StringGraphType))] + public static string Field1() => "hello"; + } + + [Fact] + public async Task Concurrent() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(false); + } + + public class CConcurrent : DIObjectGraphBase + { + [Concurrent] + public static Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public void ConcurrentIgnoredForSynchronousMethods() + { + Configure(); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CConcurrentIgnoredForSynchronousMethods : DIObjectGraphBase + { + [Concurrent] + public static string Field1() => "hello"; + } + + [Fact] + public async Task AlwaysConcurrentForStatic() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(false); + } + + public class CAlwaysConcurrentForStatic : DIObjectGraphBase + { + public static Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public async Task NotScopedWhenNoServices() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(false); + } + + public class CNotScopedWhenNoServices : DIObjectGraphBase + { + [Concurrent(true)] + public static Task Field1() => Task.FromResult("hello"); + } + + [Fact] + public async Task AlwaysConcurrentForStaticUnlessService() + { + Configure(); + _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns("hello").Verifiable(); + await VerifyFieldAsync("Field1", true, false, "hello"); + Verify(false); + } + + public class CAlwaysConcurrentForStaticUnlessService : DIObjectGraphBase + { + public static Task Field1([FromServices] string value) => Task.FromResult(value); + } + + [Fact] + public async Task ScopedOnlyWhenSpecifiedWithServices() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(true); + } + + public class CScopedOnlyWhenSpecified : DIObjectGraphBase + { + [Concurrent(true)] + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + } + + [Fact] + public async Task InheritsConcurrent() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(true); + } + + [Concurrent(true)] + public class CInheritsConcurrent : DIObjectGraphBase + { + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + } + + [Fact] + public async Task InheritedConcurrentOverridable() + { + Configure(); + await VerifyFieldAsync("Field1", true, false, "hello"); + Verify(false); + } + + [Concurrent(true)] + public class CInheritedConcurrentOverridable : DIObjectGraphBase + { + [Concurrent(Concurrent = false)] + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + } + } +} diff --git a/Tests/DIObjectGraphTypeTests/Graph.cs b/Tests/DIObjectGraphTypeTests/Graph.cs new file mode 100644 index 0000000..7b39e94 --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/Graph.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel; +using GraphQL.DI; +using Shouldly; +using Xunit; + +namespace DIObjectGraphTypeTests +{ + public class Graph : DIObjectGraphTypeTestBase + { + [Fact] + public void GraphName() + { + Configure().Name.ShouldBe("TestGraphName"); + } + + [Name("TestGraphName")] + public class CGraphName : DIObjectGraphBase { } + + [Fact] + public void GraphDescription() + { + Configure().Description.ShouldBe("TestGraphDescription"); + } + + [Description("TestGraphDescription")] + public class CGraphDescription : DIObjectGraphBase { } + + [Fact] + public void GraphObsolete() + { + Configure().DeprecationReason.ShouldBe("TestDeprecationReason"); + } + + [Obsolete("TestDeprecationReason")] + public class CGraphObsolete : DIObjectGraphBase { } + + [Fact] + public void GraphMetadata() + { + Configure().GetMetadata("test").ShouldBe("value"); + } + + [Metadata("test", "value")] + public class CGraphMetadata : DIObjectGraphBase { } + } +} diff --git a/Tests/DIObjectGraphTypeTests/Services.cs b/Tests/DIObjectGraphTypeTests/Services.cs new file mode 100644 index 0000000..a81ef9f --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/Services.cs @@ -0,0 +1,51 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using GraphQL.DI; +using GraphQL.Types; +using Shouldly; +using Xunit; + +namespace DIObjectGraphTypeTests +{ + public class Services : DIObjectGraphTypeTestBase + { + [Fact] + public void Service() + { + Configure(); + _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns("hello").Verifiable(); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CService : DIObjectGraphBase + { + public static string Field1([FromServices] string arg) => arg; + } + + [Fact] + public void ServiceMissingThrows() + { + Configure(); + _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns((string)null).Verifiable(); + Should.Throw(() => VerifyField("Field1", true, false, "hello")); + Verify(false); + } + + [Fact] + public async Task ScopedService() + { + Configure(); + _scopedServiceProviderMock.Setup(x => x.GetService(typeof(string))).Returns("hello").Verifiable(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(true); + } + + public class CScopedService : DIObjectGraphBase + { + [Concurrent(true)] + public static Task Field1([FromServices] string arg) => Task.FromResult(arg); + } + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 4fb0aec..a6c059d 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 false + 9.0 diff --git a/src/ConcurrentAttribute.cs b/src/ConcurrentAttribute.cs index 1eeeb7c..3a8b00f 100644 --- a/src/ConcurrentAttribute.cs +++ b/src/ConcurrentAttribute.cs @@ -7,6 +7,7 @@ public class ConcurrentAttribute : Attribute { public ConcurrentAttribute() { } public ConcurrentAttribute(bool createNewScope) { CreateNewScope = createNewScope; } - public bool CreateNewScope { get; } + public bool Concurrent { get; set; } = true; + public bool CreateNewScope { get; set; } = false; } } diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index 3bddfc4..535d3f0 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -34,6 +34,12 @@ public DIObjectGraphType() //pull metadata foreach (var metadataAttribute in classType.GetCustomAttributes()) Metadata.Add(metadataAttribute.Key, metadataAttribute.Value); + //check if there is a default concurrency setting + var concurrentAttribute = classType.GetCustomAttribute(); + if (concurrentAttribute != null) { + DefaultConcurrent = true; + DefaultCreateScope = concurrentAttribute.CreateNewScope; + } //give inherited classes a chance to mutate the field type list before they are added to the graph type list var fieldTypes = CreateFieldTypeList(); @@ -50,6 +56,9 @@ public DIObjectGraphType() private static readonly PropertyInfo _requestServicesProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.RequestServices), BindingFlags.Instance | BindingFlags.Public); private static readonly PropertyInfo _cancellationTokenProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.CancellationToken), BindingFlags.Public | BindingFlags.Instance); + protected bool DefaultConcurrent { get; set; } = false; + protected bool DefaultCreateScope { get; set; } = false; + protected virtual List CreateFieldTypeList() { //scan for public members @@ -126,26 +135,36 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) //set the resolver to run the compiled resolve function resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); } - //for methods that return a Task and are marked with the Concurrent attribute, - else if (isAsync && method.GetCustomAttributes().Any()) { - //mark this field as concurrent, so the execution strategy will run it asynchronously - concurrent = true; - //determine if a new DI scope is required - if (method.GetCustomAttributes().Any(x => x.CreateNewScope)) { - //the resolve function needs to create a scope, - // then run the compiled resolve function (which creates an instance of the class), - // then release the scope once the task has been awaited - resolver = CreateScopedResolver(exprResolve, resolveFieldContextParameter); - } else { - //just run the compiled resolve function, and count on the method to handle multithreading issues + else { + var methodConcurrent = method.GetCustomAttribute(); + concurrent = DefaultConcurrent; + var scoped = DefaultCreateScope; + if (methodConcurrent != null) { + concurrent = methodConcurrent.Concurrent; + scoped = methodConcurrent.CreateNewScope; + } + //for methods that return a Task and are marked with the Concurrent attribute, + if (isAsync && concurrent) { + //mark this field as concurrent, so the execution strategy will run it asynchronously + concurrent = true; + //determine if a new DI scope is required + if (scoped) { + //the resolve function needs to create a scope, + // then run the compiled resolve function (which creates an instance of the class), + // then release the scope once the task has been awaited + resolver = CreateScopedResolver(exprResolve, resolveFieldContextParameter); + } else { + //just run the compiled resolve function, and count on the method to handle multithreading issues + resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); + } + } + //for non-async methods, and instance methods that are not marked with the Concurrent attribute + else { + concurrent = false; + //just run the compiled resolve function resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); } } - //for non-async methods, and instance methods that are not marked with the Concurrent attribute - else { - //just run the compiled resolve function - resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); - } } //process the method's attributes and add the field From 606ada5d871a461361536cf1d6d514ebda03e617 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Mon, 22 Mar 2021 16:23:36 -0400 Subject: [PATCH 04/31] Add XML comments --- Tests/DIObjectGraphTypeTests/Graph.cs | 19 +++++ Tests/Tests.csproj | 2 +- src/ConcurrentAttribute.cs | 22 +++++- src/DIDocumentExecuter.cs | 45 ++++++++--- src/DIExecutionStrategy.cs | 22 ++---- src/DIFieldType.cs | 4 + src/DIObjectGraphBase.cs | 8 ++ src/DIObjectGraphType.cs | 106 ++++++++++++++++++++------ src/FromServicesAttribute.cs | 5 ++ src/FromSourceAttribute.cs | 5 ++ src/GraphTypeAttribute.cs | 16 ++-- src/MetadataAttribute.cs | 11 +++ src/NameAttribute.cs | 11 ++- src/RequiredAttribute.cs | 5 +- src/Shane32.GraphQL.DI.csproj | 1 + src/TaskExtensions.cs | 50 ------------ 16 files changed, 222 insertions(+), 110 deletions(-) delete mode 100644 src/TaskExtensions.cs diff --git a/Tests/DIObjectGraphTypeTests/Graph.cs b/Tests/DIObjectGraphTypeTests/Graph.cs index 7b39e94..b8cc273 100644 --- a/Tests/DIObjectGraphTypeTests/Graph.cs +++ b/Tests/DIObjectGraphTypeTests/Graph.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.ComponentModel; +using System.Reflection; using GraphQL.DI; using Shouldly; using Xunit; @@ -43,5 +45,22 @@ public void GraphMetadata() [Metadata("test", "value")] public class CGraphMetadata : DIObjectGraphBase { } + + [Fact] + public void CanOverrideMembers() + { + var test = new CCanOverrideMembersGraphType(); + test.Fields.Count.ShouldBe(0); + } + + public class CCanOverrideMembersGraphType : DIObjectGraphType + { + protected override IEnumerable GetMethodsToProcess() => Array.Empty(); + } + + public class CCanOverrideMembers : DIObjectGraphBase + { + public static string Field1() => "hello"; + } } } diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index a6c059d..d216c16 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -8,7 +8,7 @@ - 1701;1702;1591 + 1701;1702;1591;IDE1006;IDE0060;0618 diff --git a/src/ConcurrentAttribute.cs b/src/ConcurrentAttribute.cs index 3a8b00f..a4bf974 100644 --- a/src/ConcurrentAttribute.cs +++ b/src/ConcurrentAttribute.cs @@ -2,12 +2,32 @@ namespace GraphQL.DI { + /// + /// Marks this class or method as being able to run concurrently. May specify if a new service + /// scope is required. + /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] - public class ConcurrentAttribute : Attribute + public sealed class ConcurrentAttribute : Attribute { + /// + /// Marks this class or method as being able to run concurrently without a dedicated service scope. + /// public ConcurrentAttribute() { } + + /// + /// Marks this class or method as being able to run concurrently, with or without a dedicated service scope. + /// public ConcurrentAttribute(bool createNewScope) { CreateNewScope = createNewScope; } + + /// + /// Indicates if this class or method is able to run concurrently. + /// public bool Concurrent { get; set; } = true; + + /// + /// Indicates if this class or method requires a dedicated service scope to run concurrently. When set + /// for a class, a new service scope will be created for each method called. + /// public bool CreateNewScope { get; set; } = false; } } diff --git a/src/DIDocumentExecuter.cs b/src/DIDocumentExecuter.cs index eb8b2ce..5387662 100644 --- a/src/DIDocumentExecuter.cs +++ b/src/DIDocumentExecuter.cs @@ -1,4 +1,5 @@ using System; +using GraphQL.Types; using GraphQL.Execution; using GraphQL.Language.AST; using GraphQL.Validation; @@ -7,23 +8,43 @@ namespace GraphQL.DI { - //DIDocumentExecuter is designed to be registered as a singleton + /// + /// Processes an entire GraphQL request, given an input GraphQL request string. This + /// is intended to be called by user code to process a query. Uses a + /// implementation for and . Can be passed + /// a implementation for . + /// public class DIDocumentExecuter : DocumentExecuter { + /// + /// The instance of the execution strategy used for and . + /// protected IExecutionStrategy DIExecutionStrategy = DI.DIExecutionStrategy.Instance; - protected IExecutionStrategy SubscriptionExecutionStrategy = null; + /// + /// The instance of the execution strategy used for . + /// + protected IExecutionStrategy? SubscriptionExecutionStrategy = null; + /// + /// Initializes a new instance without support for subscriptions. + /// public DIDocumentExecuter() : base() { } - public DIDocumentExecuter(IExecutionStrategy subscriptionExecutionStrategy) : base() + /// + /// Initializes a new instance with the specified for . + /// + public DIDocumentExecuter(IExecutionStrategy? subscriptionExecutionStrategy) : base() { SubscriptionExecutionStrategy = subscriptionExecutionStrategy; } - //pull IDocumentBuilder, IDocumentValidator, and IComplexityAnalyzer from DI if they have been registered - //if any of them have not been registered, use default implementations + /// + /// Initializes a new instance using the specified to pull optional + /// references to , and . + /// Does not support subscriptions. + /// public DIDocumentExecuter( IServiceProvider serviceProvider) : base( (serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider))).GetService() ?? new GraphQLDocumentBuilder(), @@ -32,13 +53,17 @@ public DIDocumentExecuter( { } - //pull IDocumentBuilder, IDocumentValidator, and IComplexityAnalyzer from DI if they have been registered - //if any of them have not been registered, use default implementations - public DIDocumentExecuter(IServiceProvider serviceProvider, IExecutionStrategy subscriptionExecutionStrategy) : this(serviceProvider) + /// + /// Initializes a new instance using the specified to pull optional + /// references to , and . + /// Uses the specified for . + /// + public DIDocumentExecuter(IServiceProvider serviceProvider, IExecutionStrategy? subscriptionExecutionStrategy) : this(serviceProvider) { SubscriptionExecutionStrategy = subscriptionExecutionStrategy; } + /// protected override IExecutionStrategy SelectExecutionStrategy(ExecutionContext context) { switch (context.Operation.OperationType) @@ -50,10 +75,10 @@ protected override IExecutionStrategy SelectExecutionStrategy(ExecutionContext c return DIExecutionStrategy; case OperationType.Subscription: - return SubscriptionExecutionStrategy; + return SubscriptionExecutionStrategy ?? base.SelectExecutionStrategy(context); default: - throw new InvalidOperationException($"Unexpected OperationType {context.Operation.OperationType}"); + return base.SelectExecutionStrategy(context); } } diff --git a/src/DIExecutionStrategy.cs b/src/DIExecutionStrategy.cs index 04fe013..9544045 100644 --- a/src/DIExecutionStrategy.cs +++ b/src/DIExecutionStrategy.cs @@ -7,10 +7,16 @@ namespace GraphQL.DI { + /// + /// An implementation for use with field types. + /// Will respect to execute nodes synchronously or concurrently. + /// Does not call . + /// public class DIExecutionStrategy : ExecutionStrategy { internal static DIExecutionStrategy Instance = new DIExecutionStrategy(); + /// protected override async Task ExecuteNodeTreeAsync(ExecutionContext context, ObjectExecutionNode rootNode) { Func> taskFunc = async (task, node) => { await task; return node; }; @@ -20,7 +26,7 @@ protected override async Task ExecuteNodeTreeAsync(ExecutionContext context, Obj var asyncNodes = new Stack(); //asynchronous nodes to be executed var waitingTasks = new List>(); //nodes currently executing var pendingNodes = new Queue(); //IDelayLoadedResult nodes pending completion - Task waitingSyncTask = null; + Task? waitingSyncTask = null; int maxTasks = context.MaxParallelExecutionCount ?? int.MaxValue; if (maxTasks < 1) throw new InvalidOperationException("Invalid maximum number of tasks"); @@ -86,18 +92,10 @@ void DICompleteNode(ExecutionNode node) //complete one or more asynchronously-executing tasks if (waitingTasks.Count == 1) { - await OnBeforeExecutionStepAwaitedAsync(context) - .ConfigureAwait(false); - DICompleteNode(await waitingTasks[0]); waitingTasks.Clear(); waitingSyncTask = null; } else if (waitingTasks.Count > 0) { - //wait for listeners (this really makes no sense, and - // is a really poor way of implementing an IDataLoader) - await OnBeforeExecutionStepAwaitedAsync(context) - .ConfigureAwait(false); - //wait for at least one task to complete var completedTask = await Task.WhenAny(waitingTasks).ConfigureAwait(false); //note: errors are not thrown here, but rather down at task.Result @@ -127,12 +125,6 @@ await OnBeforeExecutionStepAwaitedAsync(context) while (pendingNodes.Count > 0) { var pendingNode = pendingNodes.Dequeue(); var task = CompleteDataLoaderNodeAsync(context, pendingNode); - if (!task.IsCompleted) { - //wait for listeners (this really makes no sense, and - // is a really poor way of implementing an IDataLoader) - await OnBeforeExecutionStepAwaitedAsync(context) - .ConfigureAwait(false); - } await task.ConfigureAwait(false); //execute synchronously DICompleteNode(pendingNode); } diff --git a/src/DIFieldType.cs b/src/DIFieldType.cs index 5f31364..71c0fa8 100644 --- a/src/DIFieldType.cs +++ b/src/DIFieldType.cs @@ -2,8 +2,12 @@ namespace GraphQL.DI { + /// public class DIFieldType : FieldType { + /// + /// Indicates if the field resolver can run concurrently with other field resolvers. + /// public bool Concurrent { get; set; } = false; } } diff --git a/src/DIObjectGraphBase.cs b/src/DIObjectGraphBase.cs index 0fcab66..155467e 100644 --- a/src/DIObjectGraphBase.cs +++ b/src/DIObjectGraphBase.cs @@ -1,5 +1,9 @@ namespace GraphQL.DI { + /// + /// This is a required base type of all DI-created graph types. may be + /// used if the type is . + /// //this class is a placeholder for future support of properties or methods on the base class public class DIObjectGraphBase { @@ -8,6 +12,10 @@ public class DIObjectGraphBase //with DI, any objects necessary could be brought in via dependency injection (such as Schema), so they really don't need to be in here } + /// + /// This is a required base type of all DI-created graph types. may be + /// used when the type is not . + /// public class DIObjectGraphBase : DIObjectGraphBase { } diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index 535d3f0..c990a79 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -10,13 +10,26 @@ using GraphQL.MicrosoftDI; using GraphQL.Resolvers; using GraphQL.Types; +using GraphQL.Utilities; using Microsoft.Extensions.DependencyInjection; namespace GraphQL.DI { + /// + /// Wraps a graph type for use with GraphQL. This class should be registered as a singleton + /// within your dependency injection provider. + /// public class DIObjectGraphType : DIObjectGraphType where TDIGraph : DIObjectGraphBase { } + /// + /// Wraps a graph type for use with GraphQL. This class should be registered as a singleton + /// within your dependency injection provider. + /// public class DIObjectGraphType : ObjectGraphType where TDIGraph : DIObjectGraphBase { + /// + /// Initializes a new instance, configuring the , , + /// and properties. + /// public DIObjectGraphType() { var classType = typeof(TDIGraph); @@ -56,15 +69,25 @@ public DIObjectGraphType() private static readonly PropertyInfo _requestServicesProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.RequestServices), BindingFlags.Instance | BindingFlags.Public); private static readonly PropertyInfo _cancellationTokenProperty = typeof(IResolveFieldContext).GetProperty(nameof(IResolveFieldContext.CancellationToken), BindingFlags.Public | BindingFlags.Instance); + /// + /// Gets or sets whether fields added to this graph type will default to running concurrently. + /// protected bool DefaultConcurrent { get; set; } = false; + /// + /// Gets or sets whether concurrent fields added to this graph type will default to running in a dedicated service scope. + /// protected bool DefaultCreateScope { get; set; } = false; + /// + /// Returns a list of instances representing the fields ready to be + /// added to the graph type. + /// protected virtual List CreateFieldTypeList() { //scan for public members var methods = GetMethodsToProcess(); var fieldTypeList = new List(methods.Count()); - foreach (var method in methods.Where(x => !x.ContainsGenericParameters)) { + foreach (var method in methods) { var fieldType = ProcessMethod(method); if (fieldType != null) fieldTypeList.Add(fieldType); @@ -72,12 +95,20 @@ protected virtual List CreateFieldTypeList() return fieldTypeList; } + /// + /// Returns a list of methods ( instances) on the class to be + /// converted into field definitions. + /// protected virtual IEnumerable GetMethodsToProcess() { - return typeof(TDIGraph).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); + return typeof(TDIGraph).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(x => !x.ContainsGenericParameters); } - protected virtual DIFieldType ProcessMethod(MethodInfo method) + + /// + /// Converts a specified method ( instance) into a field definition. + /// + protected virtual DIFieldType? ProcessMethod(MethodInfo method) { //get the method name string methodName = method.Name; @@ -177,10 +208,9 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) } //determine the graphtype of the field var graphTypeAttribute = method.GetCustomAttribute(); - Type graphType = graphTypeAttribute?.Type; - IGraphType graphTypeResolved = graphTypeAttribute?.ResolvedType; + Type? graphType = graphTypeAttribute?.Type; //infer the graphtype if it is not specified - if (graphType == null && graphTypeResolved == null) { + if (graphType == null) { if (method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { graphType = InferOutputGraphType(method.ReturnType.GetGenericArguments()[0], isRequired); } else { @@ -188,13 +218,12 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) } } //load the description - string description = method.GetCustomAttribute()?.Description; + string? description = method.GetCustomAttribute()?.Description; //load the deprecation reason - string obsoleteDescription = method.GetCustomAttribute()?.Message; + string? obsoleteDescription = method.GetCustomAttribute()?.Message; //create the field var fieldType = new DIFieldType() { Type = graphType, - ResolvedType = graphTypeResolved, Name = methodName, Arguments = new QueryArguments(queryArguments.ToArray()), Resolver = resolver, @@ -211,27 +240,48 @@ protected virtual DIFieldType ProcessMethod(MethodInfo method) } + /// + /// Returns a GraphQL input type for a specified CLR type + /// protected virtual Type InferInputGraphType(Type type, bool isRequired) { return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.InputType); } + /// + /// Returns a GraphQL output type for a specified CLR type + /// protected virtual Type InferOutputGraphType(Type type, bool isRequired) { return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.OutputType); } + /// + /// Returns an expression that gets/creates an instance of from a . + /// Defaults to the following: + /// context => context.RequestServices.GetRequiredService<TDIGraph>(); + /// protected virtual Expression GetInstanceExpression(ParameterExpression resolveFieldContextParameter) { return GetServiceExpression(resolveFieldContextParameter, typeof(TDIGraph)); } + /// + /// Returns an expression that returns an from a . + /// Defaults to the following: + /// context => context.RequestServices. + /// protected virtual Expression GetServiceProviderExpression(ParameterExpression resolveFieldContextParameter) { //returns: context.RequestServices return Expression.Property(resolveFieldContextParameter, _requestServicesProperty); } + /// + /// Returns an expression that gets/creates an instance of the specified type from a . + /// Defaults to the following: + /// context => context.RequestServices.GetRequiredService<T>(); + /// protected virtual Expression GetServiceExpression(ParameterExpression resolveFieldContextParameter, Type serviceType) { //returns: (serviceType)(context.RequestServices.GetRequiredService(serviceType)) @@ -242,7 +292,10 @@ protected virtual Expression GetServiceExpression(ParameterExpression resolveFie return cast; } - private ConcurrentDictionary _funcFieldResolverConstructors = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _funcFieldResolverConstructors = new ConcurrentDictionary(); + /// + /// Returns a field resolver for a specified delegate expression. Does not create a dedicated service scope for the delegate. + /// protected virtual IFieldResolver CreateUnscopedResolver(Expression resolveExpression, ParameterExpression resolveFieldContextParameter) { var constructorInfo = _funcFieldResolverConstructors.GetOrAdd(resolveExpression.Type, t => typeof(FuncFieldResolver<>).MakeGenericType(t).GetConstructors().Single()); @@ -250,8 +303,11 @@ protected virtual IFieldResolver CreateUnscopedResolver(Expression resolveExpres return (IFieldResolver)constructorInfo.Invoke(new[] { lambda }); } - private ConcurrentDictionary _scopedFieldResolverConstructors = new ConcurrentDictionary(); - private ConcurrentDictionary _scopedAsyncFieldResolverConstructors = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _scopedFieldResolverConstructors = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _scopedAsyncFieldResolverConstructors = new ConcurrentDictionary(); + /// + /// Returns a field resolver for a specified delegate expression. The field resolver creates a dedicated service scope for the delegate. + /// protected virtual IFieldResolver CreateScopedResolver(Expression resolveExpression, ParameterExpression resolveFieldContextParameter) { ConstructorInfo constructorInfo; @@ -274,7 +330,13 @@ private static Type GetTaskType(Type t) throw new ArgumentOutOfRangeException(nameof(t), "Type does not inherit from Task<>."); } - protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInfo param, ParameterExpression resolveFieldContextParameter, out bool usesServices, out Expression expr) + /// + /// Processes a parameter of a method, returning an expression based upon , and + /// optionally returns a query argument to be added to the field. can be set to + /// to indicate that the parameter uses the service provider and may need to run within + /// a scoped service provider for concurrent use. + /// + protected virtual QueryArgument? ProcessParameter(MethodInfo method, ParameterInfo param, ParameterExpression resolveFieldContextParameter, out bool usesServices, out Expression expr) { usesServices = false; @@ -352,27 +414,23 @@ protected virtual QueryArgument ProcessParameter(MethodInfo method, ParameterInf //load the specified graph type var graphTypeAttribute = param.GetCustomAttribute(); - Type graphType = graphTypeAttribute?.Type; - IGraphType graphTypeResolved = graphTypeAttribute?.ResolvedType; + Type? graphType = graphTypeAttribute?.Type; //if no specific graphtype set, pull from registered graph type list - if (graphType == null && graphTypeResolved == null) { + if (graphType == null) { graphType = InferInputGraphType(param.ParameterType, isRequired); } //construct the query argument - QueryArgument argument; - if (graphType != null) - argument = new QueryArgument(graphType); - else - argument = new QueryArgument(graphTypeResolved); + var argument = new QueryArgument(graphType) { + Name = nameAttribute?.Name ?? param.Name, + Description = param.GetCustomAttribute()?.Description, + }; - argument.Name = nameAttribute?.Name ?? param.Name; - argument.Description = param.GetCustomAttribute()?.Description; foreach (var metaAttribute in param.GetCustomAttributes()) argument.Metadata.Add(metaAttribute.Key, metaAttribute.Value); //pull/create the default value - object defaultValue = null; + object? defaultValue = null; if (param.IsOptional) { defaultValue = param.DefaultValue; } else if (param.ParameterType.IsValueType) { diff --git a/src/FromServicesAttribute.cs b/src/FromServicesAttribute.cs index 9e042c2..b5dba35 100644 --- a/src/FromServicesAttribute.cs +++ b/src/FromServicesAttribute.cs @@ -2,6 +2,11 @@ namespace GraphQL.DI { + /// + /// Marks an parameter (query argument) as being pulled from . + /// The type of this parameter must match the source type as specified in the generic type parameter of + /// . For , the type must be . + /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public class FromServicesAttribute : Attribute { diff --git a/src/FromSourceAttribute.cs b/src/FromSourceAttribute.cs index f9ee832..9cc32a4 100644 --- a/src/FromSourceAttribute.cs +++ b/src/FromSourceAttribute.cs @@ -2,6 +2,11 @@ namespace GraphQL.DI { + /// + /// Marks an parameter (query argument) as being pulled via . + /// For concurrent fields specified to run in a separate scope, the service will be pulled from the dedicated + /// service scope created for that field resolver. + /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public class FromSourceAttribute : Attribute { diff --git a/src/GraphTypeAttribute.cs b/src/GraphTypeAttribute.cs index f4ae93e..1da3f5c 100644 --- a/src/GraphTypeAttribute.cs +++ b/src/GraphTypeAttribute.cs @@ -3,21 +3,23 @@ namespace GraphQL.DI { + /// + /// Marks a method's (field's) return value to be the specified GraphQL type, or + /// marks a parameter's (query argument's) input value to be the specified GraphQL type. + /// //perhaps this should apply to ReturnValue rather than Method [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class GraphTypeAttribute : Attribute { + /// public GraphTypeAttribute(Type graphType) { Type = graphType; } - public GraphTypeAttribute(IGraphType graphType) - { - ResolvedType = graphType; - } - - public Type Type { get; private set; } - public IGraphType ResolvedType { get; private set; } + /// + /// Returns the graph type specified for the method (field) or parameter (query argument). + /// + public Type Type { get; } } } diff --git a/src/MetadataAttribute.cs b/src/MetadataAttribute.cs index a88200b..e367a51 100644 --- a/src/MetadataAttribute.cs +++ b/src/MetadataAttribute.cs @@ -2,16 +2,27 @@ namespace GraphQL.DI { + /// + /// Marks a class (graph type), method (field) or parameter (query argument) with additional metadata. + /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)] public class MetadataAttribute : Attribute { + /// public MetadataAttribute(string key, object value) { Key = key; Value = value; } + /// + /// Gets or sets the metadata key. + /// public string Key { get; set; } + + /// + /// Gets or sets the metadata value. + /// public object Value { get; set; } } } diff --git a/src/NameAttribute.cs b/src/NameAttribute.cs index 191f4b9..e4aefb2 100644 --- a/src/NameAttribute.cs +++ b/src/NameAttribute.cs @@ -1,15 +1,24 @@ using System; +using GraphQL.Conversion; namespace GraphQL.DI { + /// + /// Marks a class (graph type), method (field) or parameter (query argument) with a specified GraphQL name. + /// Note that the specified name will be translated by the schema's . + /// [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class NameAttribute : Attribute { + /// public NameAttribute(string name) { Name = name; } - public string Name { get; private set; } + /// + /// Returns the GraphQL name of the class (graph type), method (field), or parameter (query argument). + /// + public string Name { get; } } } diff --git a/src/RequiredAttribute.cs b/src/RequiredAttribute.cs index 08fdc27..71b3931 100644 --- a/src/RequiredAttribute.cs +++ b/src/RequiredAttribute.cs @@ -2,10 +2,13 @@ namespace GraphQL.DI { + /// + /// Marks a method's (field's) return value as always non-null, or + /// marks a parameter's (query argument's) input value to be required. + /// //perhaps this should apply to ReturnValue instead of Method [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class RequiredAttribute : Attribute { - public RequiredAttribute() { } } } diff --git a/src/Shane32.GraphQL.DI.csproj b/src/Shane32.GraphQL.DI.csproj index 7d35e93..58f1383 100644 --- a/src/Shane32.GraphQL.DI.csproj +++ b/src/Shane32.GraphQL.DI.csproj @@ -2,6 +2,7 @@ netstandard2.0 + enable diff --git a/src/TaskExtensions.cs b/src/TaskExtensions.cs deleted file mode 100644 index 58bc697..0000000 --- a/src/TaskExtensions.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.CSharp.RuntimeBinder; - -namespace GraphQL -{ - /// - /// Task extensions. - /// - internal static class TaskExtensions - { - /// - /// Gets the result of a completed when TResult is not known - /// - /// - /// The Task should already be awaited or this call will block. - /// This will also throw an exception if the task is not Task<TResult>. - /// - /// A task that has already been awaited - /// - internal static object GetResult(this Task task) - { - if (task is Task to) { - // Most performant if available - return to.Result; - } else { - // Using dynamic is over 10x faster than reflection but works only for public types (or with InternalsVisibleTo attribute) - try { - return ((dynamic)task).Result; - } catch (RuntimeBinderException) { - // it won't be any worse - return task.GetType().GetProperty("Result").GetValue(task, null); - } - } - } - - internal static async Task> WhereAsync(this IEnumerable items, Func> predicate) - { - if (items == null) { - return Enumerable.Empty(); - } - - var itemTaskList = items.Select(item => new { Item = item, PredTask = predicate.Invoke(item) }).ToList(); - await Task.WhenAll(itemTaskList.Select(x => x.PredTask)).ConfigureAwait(false); - return itemTaskList.Where(x => x.PredTask.Result).Select(x => x.Item); - } - } -} From d63b6ac7e87f43a1119da3aedcbd121bd1e35f83 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:09:46 -0400 Subject: [PATCH 05/31] Support for nullable reference types in annotated classes --- Tests/DIObjectGraphTypeTests/Argument.cs | 16 +- .../DIObjectGraphTypeTestBase.cs | 2 +- Tests/DIObjectGraphTypeTests/Field.cs | 83 ++++++- Tests/DIObjectGraphTypeTests/Nullable.cs | 215 ++++++++++++++++++ Tests/DIObjectGraphTypeTests/Services.cs | 2 +- Tests/Extensions.cs | 12 - Tests/NullabilityTestClasses.cs | 111 +++++++++ Tests/Tests.csproj | 1 + src/DIObjectGraphType.cs | 172 ++++++++++++-- src/OptionalAttribute.cs | 14 ++ 10 files changed, 583 insertions(+), 45 deletions(-) create mode 100644 Tests/DIObjectGraphTypeTests/Nullable.cs delete mode 100644 Tests/Extensions.cs create mode 100644 Tests/NullabilityTestClasses.cs create mode 100644 src/OptionalAttribute.cs diff --git a/Tests/DIObjectGraphTypeTests/Argument.cs b/Tests/DIObjectGraphTypeTests/Argument.cs index 34876c0..9c13ce4 100644 --- a/Tests/DIObjectGraphTypeTests/Argument.cs +++ b/Tests/DIObjectGraphTypeTests/Argument.cs @@ -36,6 +36,20 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1(int? arg) => arg; } + [Fact] + public void NullableValueExplicit() + { + Configure(); + VerifyFieldArgument("Field1", "arg", true, (int?)2); + VerifyField("Field1", true, false, 2); + Verify(false); + } + + public class CNullableValueExplicit : DIObjectGraphBase + { + public static int? Field1([Optional] int arg) => arg; + } + [Fact] public void NullableObject() { @@ -47,7 +61,7 @@ public void NullableObject() public class CNullableObject : DIObjectGraphBase { - public static string Field1(string arg) => arg; + public static string Field1([Optional] string arg) => arg; } [Fact] diff --git a/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs b/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs index edf6d98..242d61f 100644 --- a/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs +++ b/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs @@ -34,7 +34,7 @@ public DIObjectGraphTypeTestBase() : base() _serviceProviderMock.Setup(x => x.GetService(typeof(IServiceScopeFactory))).Returns(_scopeFactoryMock.Object); _contextMock = new Mock(MockBehavior.Strict); _contextMock.SetupGet(x => x.RequestServices).Returns(_serviceProviderMock.Object); - _contextMock.SetupGet(x => x.Source).Returns(() => _source); + _contextMock.SetupGet(x => x.Source).Returns(() => _source!); _contextMock.SetupGet(x => x.ParentType).Returns(new ObjectGraphType()); _contextMock.SetupGet(x => x.Arguments).Returns(() => _arguments); _contextMock.SetupGet(x => x.Schema).Returns((ISchema)null); diff --git a/Tests/DIObjectGraphTypeTests/Field.cs b/Tests/DIObjectGraphTypeTests/Field.cs index ab374cc..089f5e8 100644 --- a/Tests/DIObjectGraphTypeTests/Field.cs +++ b/Tests/DIObjectGraphTypeTests/Field.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Threading.Tasks; using GraphQL; +using GraphQL.DataLoader; using GraphQL.DI; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; @@ -53,7 +54,7 @@ public class CStaticAsyncMethod : DIObjectGraphBase { public CStaticAsyncMethod() => throw new Exception(); - public static Task Field1() => Task.FromResult("hello"); + public static Task Field1() => Task.FromResult("hello"); } [Fact] @@ -66,7 +67,7 @@ public async Task InstanceAsyncMethod() public class CInstanceAsyncMethod : DIObjectGraphBase { - public Task Field1() => Task.FromResult("hello"); + public Task Field1() => Task.FromResult("hello"); } [Fact] @@ -204,7 +205,7 @@ public async Task ServiceProviderForScoped() public class CServiceProviderForScoped : DIObjectGraphBase { [Concurrent(true)] - public static Task Field1(IServiceProvider serviceProvider) => Task.FromResult(serviceProvider.GetRequiredService()); + public static Task Field1(IServiceProvider serviceProvider) => Task.FromResult(serviceProvider.GetRequiredService()); } [Fact] @@ -220,6 +221,20 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1() => null; } + [Fact] + public void NullableValueExplicit() + { + Configure(); + VerifyField("Field1", true, false, (int?)1); + Verify(false); + } + + public class CNullableValueExplicit : DIObjectGraphBase + { + [Optional] + public static int Field1() => 1; + } + [Fact] public void NonNullableValue() { @@ -247,6 +262,20 @@ public class CRequired : DIObjectGraphBase public static string Field1() => "hello"; } + [Fact] + public async Task RequiredTask() + { + Configure(); + await VerifyFieldAsync("Field1", false, true, "hello"); + Verify(false); + } + + public class CRequiredTask : DIObjectGraphBase + { + [Required] + public static Task Field1() => Task.FromResult("hello"); + } + [Fact] public void CustomType() { @@ -272,7 +301,7 @@ public async Task Concurrent() public class CConcurrent : DIObjectGraphBase { [Concurrent] - public static Task Field1() => Task.FromResult("hello"); + public static Task Field1() => Task.FromResult("hello"); } [Fact] @@ -299,7 +328,7 @@ public async Task AlwaysConcurrentForStatic() public class CAlwaysConcurrentForStatic : DIObjectGraphBase { - public static Task Field1() => Task.FromResult("hello"); + public static Task Field1() => Task.FromResult("hello"); } [Fact] @@ -313,7 +342,7 @@ public async Task NotScopedWhenNoServices() public class CNotScopedWhenNoServices : DIObjectGraphBase { [Concurrent(true)] - public static Task Field1() => Task.FromResult("hello"); + public static Task Field1() => Task.FromResult("hello"); } [Fact] @@ -327,7 +356,7 @@ public async Task AlwaysConcurrentForStaticUnlessService() public class CAlwaysConcurrentForStaticUnlessService : DIObjectGraphBase { - public static Task Field1([FromServices] string value) => Task.FromResult(value); + public static Task Field1([FromServices] string value) => Task.FromResult(value); } [Fact] @@ -341,7 +370,7 @@ public async Task ScopedOnlyWhenSpecifiedWithServices() public class CScopedOnlyWhenSpecified : DIObjectGraphBase { [Concurrent(true)] - public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } [Fact] @@ -355,7 +384,7 @@ public async Task InheritsConcurrent() [Concurrent(true)] public class CInheritsConcurrent : DIObjectGraphBase { - public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } [Fact] @@ -370,7 +399,41 @@ public async Task InheritedConcurrentOverridable() public class CInheritedConcurrentOverridable : DIObjectGraphBase { [Concurrent(Concurrent = false)] - public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); + } + + [Theory] + [InlineData("Field1", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field2", typeof(NonNullGraphType>))] + [InlineData("Field3", typeof(NonNullGraphType>))] + [InlineData("Field4", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field5", typeof(GraphQLClrOutputTypeReference))] + //[InlineData("Field6", typeof(GraphQLClrOutputTypeReference)] //Need to fix graphql-dotnet bug 2441 first + [InlineData("Field7", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field8", typeof(NonNullGraphType>))] + [InlineData("Field9", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field10", typeof(GraphQLClrOutputTypeReference))] + public void SupportsDataLoader(string fieldName, Type graphType) + { + Configure(true); + VerifyField(fieldName, graphType, false, null); + Verify(false); + } + + public class CSupportsDataLoader : DIObjectGraphBase + { + public IDataLoaderResult Field1() => null; + [Required] + public IDataLoaderResult Field2() => null; + public IDataLoaderResult Field3() => null; + [Optional] + public IDataLoaderResult Field4() => null; + public IDataLoaderResult Field5() => null; + public IDataLoaderResult Field6() => null; + public Task> Field7() => null; + public Task> Field8() => null; + public Task> Field9() => null; + public Task>> Field10() => null; } } } diff --git a/Tests/DIObjectGraphTypeTests/Nullable.cs b/Tests/DIObjectGraphTypeTests/Nullable.cs new file mode 100644 index 0000000..ef4539d --- /dev/null +++ b/Tests/DIObjectGraphTypeTests/Nullable.cs @@ -0,0 +1,215 @@ +using System; +using System.Linq; +using System.Reflection; +using GraphQL.DI; +using Shouldly; +using Tests.NullabilityTestClasses; +using Xunit; + +namespace DIObjectGraphTypeTests +{ + public class Nullable + { + //Verify... methods verify that .NET is building the classes + // with the expected attributes on them. Failure is not an + // error, but simply indicates that the Method and Argument + // tests may not be testing the anticipated scenarios + //Method and Argument should always pass + [Theory] + [InlineData(typeof(NullableClass1), 1)] //default not nullable + [InlineData(typeof(NullableClass2), 2)] //default nullable + [InlineData(typeof(NullableClass5), null)] + [InlineData(typeof(NullableClass6), null)] + [InlineData(typeof(NullableClass7), 1)] //default not nullable + [InlineData(typeof(NullableClass8), 2)] //default nullable + [InlineData(typeof(NullableClass9), null)] + [InlineData(typeof(NullableClass10), null)] + [InlineData(typeof(NullableClass11), 1)] //default not nullable + [InlineData(typeof(NullableClass12), null)] + [InlineData(typeof(NullableClass13), 1)] //default not nullable + [InlineData(typeof(NullableClass14), 2)] //default nullable + [InlineData(typeof(NullableClass15), null)] + public void VerifyTestClass(Type type, int? nullableContext) + { + var actualHasNullableContext = type.CustomAttributes.FirstOrDefault( + x => x.AttributeType.Name == "NullableContextAttribute"); + if (nullableContext == null) { + actualHasNullableContext.ShouldBeNull(); + } else { + actualHasNullableContext.ShouldNotBeNull(); + actualHasNullableContext.ConstructorArguments[0].Value.ShouldBe(nullableContext); + } + } + + [Theory] + [InlineData(typeof(NullableClass1), "Field1", false, true)] + [InlineData(typeof(NullableClass1), "Field2", false, true)] + [InlineData(typeof(NullableClass1), "Field3", false, false)] + [InlineData(typeof(NullableClass1), "Field4", false, false)] + [InlineData(typeof(NullableClass1), "Field5", false, false)] + [InlineData(typeof(NullableClass1), "Field6", false, false)] + [InlineData(typeof(NullableClass1), "Field7", false, false)] + [InlineData(typeof(NullableClass1), "Field8", false, false)] + [InlineData(typeof(NullableClass2), "Field1", false, false)] + [InlineData(typeof(NullableClass2), "Field2", false, false)] + [InlineData(typeof(NullableClass2), "Field3", false, false)] + [InlineData(typeof(NullableClass2), "Field4", false, false)] + [InlineData(typeof(NullableClass2), "Field5", false, false)] + [InlineData(typeof(NullableClass2), "Field6", false, false)] + [InlineData(typeof(NullableClass2), "Field7", false, false)] + [InlineData(typeof(NullableClass2), "Field8", false, false)] + [InlineData(typeof(NullableClass2), "Field9", false, true)] + [InlineData(typeof(NullableClass2), "Field10", false, true)] + [InlineData(typeof(NullableClass5), "Test", false, true)] + [InlineData(typeof(NullableClass6), "Field1", false, true)] + [InlineData(typeof(NullableClass6), "Field2", false, true)] + [InlineData(typeof(NullableClass7), "Field1", false, false)] + [InlineData(typeof(NullableClass7), "Field2", false, false)] + [InlineData(typeof(NullableClass7), "Field3", false, true)] + [InlineData(typeof(NullableClass8), "Field1", false, false)] + [InlineData(typeof(NullableClass8), "Field2", false, false)] + [InlineData(typeof(NullableClass8), "Field3", false, true)] + [InlineData(typeof(NullableClass8), "Field4", false, false)] + [InlineData(typeof(NullableClass9), "Field1", true, true)] + [InlineData(typeof(NullableClass10), "Field1", true, true)] + [InlineData(typeof(NullableClass11), "Field1", false, false)] + [InlineData(typeof(NullableClass11), "Field2", true, false)] + [InlineData(typeof(NullableClass12), "Field1", false, true)] + [InlineData(typeof(NullableClass12), "Field2", true, false)] + [InlineData(typeof(NullableClass12), "Field3", true, false)] + [InlineData(typeof(NullableClass12), "Field4", false, true)] + [InlineData(typeof(NullableClass13), "Field1", false, false)] + [InlineData(typeof(NullableClass13), "Field2", false, false)] + [InlineData(typeof(NullableClass14), "Field1", false, false)] + [InlineData(typeof(NullableClass14), "Field2", false, false)] + [InlineData(typeof(NullableClass15), "Field1", false, true)] + [InlineData(typeof(NullableClass15), "Field2", true, false)] + [InlineData(typeof(NullableClass15), "Field3", true, false)] + [InlineData(typeof(NullableClass15), "Field4", false, true)] + public void VerifyTestMethod(Type type, string methodName, bool hasNullable, bool hasNullableContext) + { + var method = type.GetMethod(methodName); + var actualHasNullableOnMethod = method.CustomAttributes.Any( + x => x.AttributeType.Name == "NullableAttribute"); + var actualHasNullableContext = method.CustomAttributes.Any( + x => x.AttributeType.Name == "NullableContextAttribute"); + var actualHasNullable = method.ReturnParameter.CustomAttributes.Any( + x => x.AttributeType.Name == "NullableAttribute"); + actualHasNullableOnMethod.ShouldBe(false); //should not be possible to apply the attribute here + actualHasNullable.ShouldBe(hasNullable); + actualHasNullableContext.ShouldBe(hasNullableContext); + } + + [Theory] + [InlineData(typeof(NullableClass9), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass9), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg4", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg5", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg4", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] + public void VerifyTestArgument(Type type, string methodName, string argumentName, bool hasNullable) + { + var method = type.GetMethod(methodName); + var argument = method.GetParameters().Single(x => x.Name == argumentName); + var actualHasNullable = argument.CustomAttributes.Any( + x => x.AttributeType.Name == "NullableAttribute"); + actualHasNullable.ShouldBe(hasNullable); + } + + [Theory] + [InlineData(typeof(NullableClass1), "Field1", true)] + [InlineData(typeof(NullableClass1), "Field2", false)] + [InlineData(typeof(NullableClass1), "Field3", false)] + [InlineData(typeof(NullableClass1), "Field4", true)] + [InlineData(typeof(NullableClass1), "Field5", true)] + [InlineData(typeof(NullableClass1), "Field6", false)] + [InlineData(typeof(NullableClass1), "Field7", false)] + [InlineData(typeof(NullableClass1), "Field8", true)] + [InlineData(typeof(NullableClass2), "Field1", true)] + [InlineData(typeof(NullableClass2), "Field2", false)] + [InlineData(typeof(NullableClass2), "Field3", false)] + [InlineData(typeof(NullableClass2), "Field4", true)] + [InlineData(typeof(NullableClass2), "Field5", true)] + [InlineData(typeof(NullableClass2), "Field6", false)] + [InlineData(typeof(NullableClass2), "Field7", true)] + [InlineData(typeof(NullableClass2), "Field8", true)] + [InlineData(typeof(NullableClass2), "Field9", false)] + [InlineData(typeof(NullableClass2), "Field10", true)] + [InlineData(typeof(NullableClass5), "Test", false)] + [InlineData(typeof(NullableClass6), "Field1", false)] + [InlineData(typeof(NullableClass6), "Field2", true)] + [InlineData(typeof(NullableClass7), "Field1", false)] + [InlineData(typeof(NullableClass7), "Field2", false)] + [InlineData(typeof(NullableClass7), "Field3", true)] + [InlineData(typeof(NullableClass8), "Field1", true)] + [InlineData(typeof(NullableClass8), "Field2", true)] + [InlineData(typeof(NullableClass8), "Field3", false)] + [InlineData(typeof(NullableClass8), "Field4", false)] + [InlineData(typeof(NullableClass9), "Field1", false)] + [InlineData(typeof(NullableClass10), "Field1", true)] + [InlineData(typeof(NullableClass11), "Field1", false)] + [InlineData(typeof(NullableClass11), "Field2", true)] + [InlineData(typeof(NullableClass12), "Field1", false)] + [InlineData(typeof(NullableClass12), "Field2", true)] + [InlineData(typeof(NullableClass12), "Field3", true)] + [InlineData(typeof(NullableClass12), "Field4", true)] + [InlineData(typeof(NullableClass13), "Field1", false)] + [InlineData(typeof(NullableClass13), "Field2", false)] + [InlineData(typeof(NullableClass14), "Field1", true)] + [InlineData(typeof(NullableClass14), "Field2", true)] + [InlineData(typeof(NullableClass15), "Field1", false)] + [InlineData(typeof(NullableClass15), "Field2", true)] + [InlineData(typeof(NullableClass15), "Field3", true)] + [InlineData(typeof(NullableClass15), "Field4", true)] + public void Method(Type type, string methodName, bool expected) + { + var method = type.GetMethod(methodName); + var nullable = TestGraphType.Instance.CheckNullability(method); + nullable.ShouldBe(expected); + } + + [Theory] + [InlineData(typeof(NullableClass9), "Field1", "arg1", true)] + [InlineData(typeof(NullableClass9), "Field1", "arg2", true)] + [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg4", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg5", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg1", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg4", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] + public void Argument(Type type, string methodName, string argumentName, bool expected) + { + var method = type.GetMethod(methodName); + var argument = method.GetParameters().Single(x => x.Name == argumentName); + var nullable = TestGraphType.Instance.CheckNullability(method, argument); + nullable.ShouldBe(expected); + } + + private class TestGraphType : DIObjectGraphType + { + public static TestGraphType Instance = new(); + public bool CheckNullability(MethodInfo method) => base.GetNullability(method); + public bool CheckNullability(MethodInfo method, ParameterInfo parameter) => base.GetNullability(method, parameter); + } + + private class TestClass : DIObjectGraphBase { } + } +} diff --git a/Tests/DIObjectGraphTypeTests/Services.cs b/Tests/DIObjectGraphTypeTests/Services.cs index a81ef9f..c367217 100644 --- a/Tests/DIObjectGraphTypeTests/Services.cs +++ b/Tests/DIObjectGraphTypeTests/Services.cs @@ -28,7 +28,7 @@ public class CService : DIObjectGraphBase public void ServiceMissingThrows() { Configure(); - _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns((string)null).Verifiable(); + _serviceProviderMock.Setup(x => x.GetService(typeof(string))).Returns((string)null!).Verifiable(); Should.Throw(() => VerifyField("Field1", true, false, "hello")); Verify(false); } diff --git a/Tests/Extensions.cs b/Tests/Extensions.cs deleted file mode 100644 index 706a145..0000000 --- a/Tests/Extensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using GraphQL.Types; -using Shouldly; - -namespace Tests -{ - public static class Extensions - { - } -} diff --git a/Tests/NullabilityTestClasses.cs b/Tests/NullabilityTestClasses.cs new file mode 100644 index 0000000..fa1828b --- /dev/null +++ b/Tests/NullabilityTestClasses.cs @@ -0,0 +1,111 @@ +#nullable enable +using System.Threading.Tasks; +using GraphQL.DataLoader; +using GraphQL.DI; + +namespace Tests.NullabilityTestClasses +{ + public class NullableClass1 + { + public static string? Field1() => "field1"; + [Required] + public static string? Field2() => "field2"; + public static int Field3() => 1; + [Optional] + public static int Field4() => 1; + public static int? Field5() => 1; + [Required] + public static int? Field6() => 1; + public static string Field7() => "field1"; + [Optional] + public static string Field8() => "field2"; + } + + public class NullableClass2 + { + public static string? Field1() => "field1"; + [Required] + public static string? Field2() => "field2"; + public static int Field3() => 1; + [Optional] + public static int Field4() => 1; + public static int? Field5() => 1; + [Required] + public static int? Field6() => 1; + public static string? Field7() => "test"; + public static string? Field8() => "test"; + public static string Field9() => "field1"; + [Optional] + public static string Field10() => "field2"; + } + + public class NullableClass5 + { + public static string Test() => "test"; + } + + public class NullableClass6 + { + public static string Field1() => "test"; + public static string? Field2() => "test"; + } + + public class NullableClass7 + { + public static string Field1() => "test"; + public static string Field2() => "test"; + public static string? Field3() => "test"; + } + + public class NullableClass8 + { + public static string? Field1() => "test"; + public static string? Field2() => "test"; + public static string Field3() => "test"; + public static int Field4() => 3; + } + + public class NullableClass9 + { + public static string Field1(string? arg1, string? arg2) => "test"; + } + + public class NullableClass10 + { + public static string? Field1(string arg1, string arg2) => "test"; + } + + public class NullableClass11 + { + public static string Field1() => "test"; + public static string? Field2(string arg1, string arg2) => "test"; + } + + public class NullableClass12 + { + public static IDataLoaderResult Field1() => null!; + public static IDataLoaderResult Field2() => null!; + public static IDataLoaderResult? Field3() => null!; + public static IDataLoaderResult? Field4() => null!; + } + + public class NullableClass13 + { + public static string Field1() => "test"; + public static string Field2(string arg1, string? arg2, int arg3, int? arg4, [Optional] string arg5) => "test"; + } + + public class NullableClass14 + { + public static string? Field1() => "test"; + public static string? Field2(string? arg1, string arg2, int arg3, int? arg4, [Required] string? arg5) => "test"; + } + + public class NullableClass15 + { + public static Task Field1() => null!; + public static Task Field2() => null!; + public static Task? Field3() => null!; + public static Task? Field4() => null!; + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index d216c16..a518743 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -5,6 +5,7 @@ false 9.0 + disable diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index c990a79..60af89e 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using GraphQL.DataLoader; using GraphQL.MicrosoftDI; using GraphQL.Resolvers; using GraphQL.Types; @@ -73,6 +74,7 @@ public DIObjectGraphType() /// Gets or sets whether fields added to this graph type will default to running concurrently. /// protected bool DefaultConcurrent { get; set; } = false; + /// /// Gets or sets whether concurrent fields added to this graph type will default to running in a dedicated service scope. /// @@ -104,7 +106,6 @@ protected virtual IEnumerable GetMethodsToProcess() return typeof(TDIGraph).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(x => !x.ContainsGenericParameters); } - /// /// Converts a specified method ( instance) into a field definition. /// @@ -165,8 +166,7 @@ protected virtual IEnumerable GetMethodsToProcess() concurrent = true; //set the resolver to run the compiled resolve function resolver = CreateUnscopedResolver(exprResolve, resolveFieldContextParameter); - } - else { + } else { var methodConcurrent = method.GetCustomAttribute(); concurrent = DefaultConcurrent; var scoped = DefaultCreateScope; @@ -201,20 +201,17 @@ protected virtual IEnumerable GetMethodsToProcess() //process the method's attributes and add the field { //determine if the field is required - var isRequired = method.GetCustomAttribute() != null || method.GetCustomAttribute() != null; - if (method.ReturnType.IsValueType && !(method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Nullable<>))) { - //non-nullable value types are implicitly required, unless they are optional - isRequired = true; - } + var isNullable = GetNullability(method); + //determine the graphtype of the field var graphTypeAttribute = method.GetCustomAttribute(); Type? graphType = graphTypeAttribute?.Type; //infer the graphtype if it is not specified if (graphType == null) { if (method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { - graphType = InferOutputGraphType(method.ReturnType.GetGenericArguments()[0], isRequired); + graphType = InferOutputGraphType(method.ReturnType.GetGenericArguments()[0], isNullable); } else { - graphType = InferOutputGraphType(method.ReturnType, isRequired); + graphType = InferOutputGraphType(method.ReturnType, isNullable); } } //load the description @@ -240,20 +237,159 @@ protected virtual IEnumerable GetMethodsToProcess() } + /// + /// Returns a boolean indicating if the return value of a method is nullable. + /// + protected virtual bool GetNullability(MethodInfo method) + { + if (method.GetCustomAttribute() != null) + return true; + if (method.GetCustomAttribute() != null) + return false; + if (method.ReturnType.IsValueType) + return method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Nullable<>); + + Nullability nullable = Nullability.Unknown; + + // check the parent type first to see if there's a nullable context attribute set for it + var parentType = method.DeclaringType; + var attribute = parentType.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && + x.ConstructorArguments.Count == 1 && + x.ConstructorArguments[0].ArgumentType == typeof(byte)); + if (attribute != null) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + // now check the method to see if there's a nullable context attribute set for it + attribute = method.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && + x.ConstructorArguments.Count == 1 && + x.ConstructorArguments[0].ArgumentType == typeof(byte)); + if (attribute != null) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + // now check the return type to see if there's a nullable attribute for it + attribute = method.ReturnParameter.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute" && + x.ConstructorArguments.Count == 1 && + (x.ConstructorArguments[0].ArgumentType == typeof(byte) || + x.ConstructorArguments[0].ArgumentType == typeof(byte[]))); + if (attribute != null && attribute.ConstructorArguments[0].ArgumentType == typeof(byte)) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + var nullabilityBytes = attribute?.ConstructorArguments[0].Value as byte[]; + var index = 0; + nullable = Consider(method.ReturnType); + return nullable != Nullability.NonNullable; + + Nullability Consider(Type t) + { + var g = t.IsGenericType ? t.GetGenericTypeDefinition() : null; + if (g == typeof(Nullable<>)) + return Nullability.Nullable; + if (t.IsValueType) + return Nullability.NonNullable; + if ((nullabilityBytes != null && nullabilityBytes[index] == (byte)Nullability.Nullable) || (nullabilityBytes == null && nullable == Nullability.Nullable)) + return Nullability.Nullable; + if (g == typeof(IDataLoaderResult<>) || g == typeof(Task<>)) { + index++; + return Consider(t.GenericTypeArguments[0]); + } + if (t == typeof(IDataLoaderResult)) + return Nullability.Nullable; + if (nullabilityBytes != null) + return (Nullability)nullabilityBytes[index]; + return nullable; + } + } + + private enum Nullability : byte + { + Unknown = 0, + NonNullable = 1, + Nullable = 2, + } + + /// + /// Returns a boolean indicating if the parameter value is nullable + /// + protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter) + { + if (parameter.GetCustomAttribute() != null) + return true; + if (parameter.GetCustomAttribute() != null) + return false; + if (parameter.ParameterType.IsValueType) + return parameter.ParameterType.IsConstructedGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>); + + Nullability nullable = Nullability.Unknown; + + // check the parent type first to see if there's a nullable context attribute set for it + var parentType = method.DeclaringType; + var attribute = parentType.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && + x.ConstructorArguments.Count == 1 && + x.ConstructorArguments[0].ArgumentType == typeof(byte)); + if (attribute != null) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + // now check the method to see if there's a nullable context attribute set for it + attribute = method.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && + x.ConstructorArguments.Count == 1 && + x.ConstructorArguments[0].ArgumentType == typeof(byte)); + if (attribute != null) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + // now check the parameter to see if there's a nullable attribute for it + attribute = parameter.CustomAttributes.FirstOrDefault(x => + x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute" && + x.ConstructorArguments.Count == 1 && + (x.ConstructorArguments[0].ArgumentType == typeof(byte) || + x.ConstructorArguments[0].ArgumentType == typeof(byte[]))); + if (attribute != null && attribute.ConstructorArguments[0].ArgumentType == typeof(byte)) { + nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; + } + + var nullabilityBytes = attribute?.ConstructorArguments[0].Value as byte[]; + var index = 0; + nullable = Consider(parameter.ParameterType); + return nullable != Nullability.NonNullable; + + Nullability Consider(Type t) + { + var g = t.IsGenericType ? t.GetGenericTypeDefinition() : null; + if (g == typeof(Nullable<>)) + return Nullability.Nullable; + if (t.IsValueType) + return Nullability.NonNullable; + if ((nullabilityBytes != null && nullabilityBytes[index] == (byte)Nullability.Nullable) || (nullabilityBytes == null && nullable == Nullability.Nullable)) + return Nullability.Nullable; + if (nullabilityBytes != null) + return (Nullability)nullabilityBytes[index]; + return nullable; + } + } + /// /// Returns a GraphQL input type for a specified CLR type /// - protected virtual Type InferInputGraphType(Type type, bool isRequired) + protected virtual Type InferInputGraphType(Type type, bool nullable) { - return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.InputType); + return type.GetGraphTypeFromType(nullable, TypeMappingMode.InputType); } /// /// Returns a GraphQL output type for a specified CLR type /// - protected virtual Type InferOutputGraphType(Type type, bool isRequired) + protected virtual Type InferOutputGraphType(Type type, bool nullable) { - return type.GetGraphTypeFromType(!isRequired, TypeMappingMode.OutputType); + return type.GetGraphTypeFromType(nullable, TypeMappingMode.OutputType); } /// @@ -406,18 +542,14 @@ private static Type GetTaskType(Type t) //initialize the query argument parameters //determine if this query argument is required - var isRequired = param.GetCustomAttribute() != null || param.GetCustomAttribute() != null; - if (param.ParameterType.IsValueType && !param.IsOptional && !(param.ParameterType.IsConstructedGenericType && param.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))) { - //non-nullable value types are implicitly required, unless they are optional - isRequired = true; - } + var nullable = GetNullability(method, param); //load the specified graph type var graphTypeAttribute = param.GetCustomAttribute(); Type? graphType = graphTypeAttribute?.Type; //if no specific graphtype set, pull from registered graph type list if (graphType == null) { - graphType = InferInputGraphType(param.ParameterType, isRequired); + graphType = InferInputGraphType(param.ParameterType, nullable); } //construct the query argument diff --git a/src/OptionalAttribute.cs b/src/OptionalAttribute.cs new file mode 100644 index 0000000..caff82b --- /dev/null +++ b/src/OptionalAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace GraphQL.DI +{ + /// + /// Marks a method's (field's) return value as nullable, or + /// marks a parameter's (query argument's) input value to be optional. + /// + //perhaps this should apply to ReturnValue instead of Method + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class OptionalAttribute : Attribute + { + } +} From a38362ec160ed504ae496ae35b45d667a3ce7216 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:16:01 -0400 Subject: [PATCH 06/31] Support required from componentmodel --- src/DIObjectGraphType.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DIObjectGraphType.cs b/src/DIObjectGraphType.cs index 60af89e..ba754ac 100644 --- a/src/DIObjectGraphType.cs +++ b/src/DIObjectGraphType.cs @@ -200,14 +200,13 @@ protected virtual IEnumerable GetMethodsToProcess() //process the method's attributes and add the field { - //determine if the field is required - var isNullable = GetNullability(method); - //determine the graphtype of the field var graphTypeAttribute = method.GetCustomAttribute(); Type? graphType = graphTypeAttribute?.Type; //infer the graphtype if it is not specified if (graphType == null) { + //determine if the field is required + var isNullable = GetNullability(method); if (method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { graphType = InferOutputGraphType(method.ReturnType.GetGenericArguments()[0], isNullable); } else { @@ -322,6 +321,8 @@ protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter return true; if (parameter.GetCustomAttribute() != null) return false; + if (parameter.GetCustomAttribute() != null) + return false; if (parameter.ParameterType.IsValueType) return parameter.ParameterType.IsConstructedGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>); @@ -541,14 +542,13 @@ private static Type GetTaskType(Type t) //otherwise, it's a query argument //initialize the query argument parameters - //determine if this query argument is required - var nullable = GetNullability(method, param); - //load the specified graph type var graphTypeAttribute = param.GetCustomAttribute(); Type? graphType = graphTypeAttribute?.Type; //if no specific graphtype set, pull from registered graph type list if (graphType == null) { + //determine if this query argument is required + var nullable = GetNullability(method, param); graphType = InferInputGraphType(param.ParameterType, nullable); } From 89fa608494f0f0fdbf69edbbe356e5d4fccb7e75 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 15:23:18 -0400 Subject: [PATCH 07/31] Update test.yml --- .github/workflows/test.yml | 71 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e4e15fe..d4b7545 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,10 @@ on: branches: - master - develop + push: + branches: + - master + - develop jobs: test: @@ -17,10 +21,10 @@ jobs: steps: - name: Checkout source uses: actions/checkout@v2 - - name: Use .NET Core 2.2 SDK + - name: Use .NET Core 2.1 LTS SDK uses: actions/setup-dotnet@v1 with: - dotnet-version: '2.2.x' + dotnet-version: '2.1.x' - name: Use .NET Core 3.1 LTS SDK uses: actions/setup-dotnet@v1 with: @@ -35,4 +39,65 @@ jobs: - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] - run: dotnet test --no-restore --no-build + run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[Shane32.ExcelLinq]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + # ==== code coverage reports (ubuntu-latest only) ==== + - name: Convert coverage report to clover & htmlsummary format + if: ${{ matrix.os == 'ubuntu-latest' }} + uses: danielpalme/ReportGenerator-GitHub-Action@4.7.1 + with: + reports: '${{ matrix.os }}.lcov.info' + targetdir: '.' + reporttypes: 'Clover;HtmlSummary' + tag: 'test_${{ github.run_number }}' + - name: Convert coverage report to html + if: ${{ matrix.os == 'ubuntu-latest' }} + uses: danielpalme/ReportGenerator-GitHub-Action@4.7.1 + with: + reports: '${{ matrix.os }}.lcov.info' + targetdir: './cloverreport' + reporttypes: 'Html' + tag: 'test_${{ github.run_number }}' + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: Code coverage artifacts + path: | + ${{ matrix.os }}.lcov.info + Clover.xml + cloverreport/** + summary.html + - name: Monitor coverage + if: ${{ matrix.os == 'ubuntu-latest' && github.event_name == 'pull_request' }} + uses: slavcodev/coverage-monitor-action@1.2.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + clover_file: "Clover.xml" + threshold_alert: 80 + threshold_warning: 90 + # https://github.com/marketplace/actions/coveralls-github-action + - name: Upload coverage to Coveralls + if: ${{ matrix.os == 'ubuntu-latest' }} + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{secrets.GITHUB_TOKEN }} + path-to-lcov: ${{ matrix.os }}.lcov.info + parallel: true + flag-name: ${{ matrix.os }} + - name: Upload coverage to Codecov + if: ${{ 0 == 1 }} + uses: codecov/codecov-action@v1 + with: + file: ${{ matrix.os }}.lcov.info + flags: unittests # optional + name: codecov-umbrella # optional + fail_ci_if_error: true # optional (default = false) + verbose: true # optional (default = false) + finish: + needs: test + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.github_token }} + parallel-finished: true From 4c1462bf05eead3778cea7d6ed7bcdf6de254f4d Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 15:25:45 -0400 Subject: [PATCH 08/31] Update test.yml --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d4b7545..8a4d34c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] - run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[Shane32.ExcelLinq]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[GraphQL.DI]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== - name: Convert coverage report to clover & htmlsummary format if: ${{ matrix.os == 'ubuntu-latest' }} From 509253f9dbc40b7453ee3e695d7d19f3b0e509d9 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:31:19 -0400 Subject: [PATCH 09/31] Move files --- Directory.Build.props | 2 +- GraphQL.DI.sln | 4 ++-- src/{ => GraphQL.DI}/ConcurrentAttribute.cs | 0 src/{ => GraphQL.DI}/DIDocumentExecuter.cs | 0 src/{ => GraphQL.DI}/DIExecutionStrategy.cs | 0 src/{ => GraphQL.DI}/DIFieldType.cs | 0 src/{ => GraphQL.DI}/DIObjectGraphBase.cs | 0 src/{ => GraphQL.DI}/DIObjectGraphType.cs | 0 src/{ => GraphQL.DI}/FromServicesAttribute.cs | 0 src/{ => GraphQL.DI}/FromSourceAttribute.cs | 0 .../GraphQL.DI.csproj} | 0 src/{ => GraphQL.DI}/GraphTypeAttribute.cs | 0 src/{ => GraphQL.DI}/MetadataAttribute.cs | 0 src/{ => GraphQL.DI}/NameAttribute.cs | 0 src/{ => GraphQL.DI}/OptionalAttribute.cs | 0 src/{ => GraphQL.DI}/RequiredAttribute.cs | 0 {Tests => src/Tests}/DIObjectGraphTypeTests/Argument.cs | 0 .../DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs | 0 {Tests => src/Tests}/DIObjectGraphTypeTests/Field.cs | 0 {Tests => src/Tests}/DIObjectGraphTypeTests/Graph.cs | 0 {Tests => src/Tests}/DIObjectGraphTypeTests/Nullable.cs | 0 {Tests => src/Tests}/DIObjectGraphTypeTests/Services.cs | 0 {Tests => src/Tests}/NullabilityTestClasses.cs | 0 {Tests => src/Tests}/Tests.csproj | 2 +- 24 files changed, 4 insertions(+), 4 deletions(-) rename src/{ => GraphQL.DI}/ConcurrentAttribute.cs (100%) rename src/{ => GraphQL.DI}/DIDocumentExecuter.cs (100%) rename src/{ => GraphQL.DI}/DIExecutionStrategy.cs (100%) rename src/{ => GraphQL.DI}/DIFieldType.cs (100%) rename src/{ => GraphQL.DI}/DIObjectGraphBase.cs (100%) rename src/{ => GraphQL.DI}/DIObjectGraphType.cs (100%) rename src/{ => GraphQL.DI}/FromServicesAttribute.cs (100%) rename src/{ => GraphQL.DI}/FromSourceAttribute.cs (100%) rename src/{Shane32.GraphQL.DI.csproj => GraphQL.DI/GraphQL.DI.csproj} (100%) rename src/{ => GraphQL.DI}/GraphTypeAttribute.cs (100%) rename src/{ => GraphQL.DI}/MetadataAttribute.cs (100%) rename src/{ => GraphQL.DI}/NameAttribute.cs (100%) rename src/{ => GraphQL.DI}/OptionalAttribute.cs (100%) rename src/{ => GraphQL.DI}/RequiredAttribute.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/Argument.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/Field.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/Graph.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/Nullable.cs (100%) rename {Tests => src/Tests}/DIObjectGraphTypeTests/Services.cs (100%) rename {Tests => src/Tests}/NullabilityTestClasses.cs (100%) rename {Tests => src/Tests}/Tests.csproj (94%) diff --git a/Directory.Build.props b/Directory.Build.props index 5eb4402..e718507 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -20,7 +20,7 @@ - + diff --git a/GraphQL.DI.sln b/GraphQL.DI.sln index eea3ce7..e0ee951 100644 --- a/GraphQL.DI.sln +++ b/GraphQL.DI.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30611.23 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shane32.GraphQL.DI", "src\Shane32.GraphQL.DI.csproj", "{72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.DI", "src\GraphQL.DI\GraphQL.DI.csproj", "{72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{B194B3FB-53C8-4C5D-ABC3-EAB6A52C674D}" ProjectSection(SolutionItems) = preProject @@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{BA5F3790-9FE0-4A10-8528-0756334AC727}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "src\Tests\Tests.csproj", "{BA5F3790-9FE0-4A10-8528-0756334AC727}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/ConcurrentAttribute.cs b/src/GraphQL.DI/ConcurrentAttribute.cs similarity index 100% rename from src/ConcurrentAttribute.cs rename to src/GraphQL.DI/ConcurrentAttribute.cs diff --git a/src/DIDocumentExecuter.cs b/src/GraphQL.DI/DIDocumentExecuter.cs similarity index 100% rename from src/DIDocumentExecuter.cs rename to src/GraphQL.DI/DIDocumentExecuter.cs diff --git a/src/DIExecutionStrategy.cs b/src/GraphQL.DI/DIExecutionStrategy.cs similarity index 100% rename from src/DIExecutionStrategy.cs rename to src/GraphQL.DI/DIExecutionStrategy.cs diff --git a/src/DIFieldType.cs b/src/GraphQL.DI/DIFieldType.cs similarity index 100% rename from src/DIFieldType.cs rename to src/GraphQL.DI/DIFieldType.cs diff --git a/src/DIObjectGraphBase.cs b/src/GraphQL.DI/DIObjectGraphBase.cs similarity index 100% rename from src/DIObjectGraphBase.cs rename to src/GraphQL.DI/DIObjectGraphBase.cs diff --git a/src/DIObjectGraphType.cs b/src/GraphQL.DI/DIObjectGraphType.cs similarity index 100% rename from src/DIObjectGraphType.cs rename to src/GraphQL.DI/DIObjectGraphType.cs diff --git a/src/FromServicesAttribute.cs b/src/GraphQL.DI/FromServicesAttribute.cs similarity index 100% rename from src/FromServicesAttribute.cs rename to src/GraphQL.DI/FromServicesAttribute.cs diff --git a/src/FromSourceAttribute.cs b/src/GraphQL.DI/FromSourceAttribute.cs similarity index 100% rename from src/FromSourceAttribute.cs rename to src/GraphQL.DI/FromSourceAttribute.cs diff --git a/src/Shane32.GraphQL.DI.csproj b/src/GraphQL.DI/GraphQL.DI.csproj similarity index 100% rename from src/Shane32.GraphQL.DI.csproj rename to src/GraphQL.DI/GraphQL.DI.csproj diff --git a/src/GraphTypeAttribute.cs b/src/GraphQL.DI/GraphTypeAttribute.cs similarity index 100% rename from src/GraphTypeAttribute.cs rename to src/GraphQL.DI/GraphTypeAttribute.cs diff --git a/src/MetadataAttribute.cs b/src/GraphQL.DI/MetadataAttribute.cs similarity index 100% rename from src/MetadataAttribute.cs rename to src/GraphQL.DI/MetadataAttribute.cs diff --git a/src/NameAttribute.cs b/src/GraphQL.DI/NameAttribute.cs similarity index 100% rename from src/NameAttribute.cs rename to src/GraphQL.DI/NameAttribute.cs diff --git a/src/OptionalAttribute.cs b/src/GraphQL.DI/OptionalAttribute.cs similarity index 100% rename from src/OptionalAttribute.cs rename to src/GraphQL.DI/OptionalAttribute.cs diff --git a/src/RequiredAttribute.cs b/src/GraphQL.DI/RequiredAttribute.cs similarity index 100% rename from src/RequiredAttribute.cs rename to src/GraphQL.DI/RequiredAttribute.cs diff --git a/Tests/DIObjectGraphTypeTests/Argument.cs b/src/Tests/DIObjectGraphTypeTests/Argument.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/Argument.cs rename to src/Tests/DIObjectGraphTypeTests/Argument.cs diff --git a/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs b/src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs rename to src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs diff --git a/Tests/DIObjectGraphTypeTests/Field.cs b/src/Tests/DIObjectGraphTypeTests/Field.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/Field.cs rename to src/Tests/DIObjectGraphTypeTests/Field.cs diff --git a/Tests/DIObjectGraphTypeTests/Graph.cs b/src/Tests/DIObjectGraphTypeTests/Graph.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/Graph.cs rename to src/Tests/DIObjectGraphTypeTests/Graph.cs diff --git a/Tests/DIObjectGraphTypeTests/Nullable.cs b/src/Tests/DIObjectGraphTypeTests/Nullable.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/Nullable.cs rename to src/Tests/DIObjectGraphTypeTests/Nullable.cs diff --git a/Tests/DIObjectGraphTypeTests/Services.cs b/src/Tests/DIObjectGraphTypeTests/Services.cs similarity index 100% rename from Tests/DIObjectGraphTypeTests/Services.cs rename to src/Tests/DIObjectGraphTypeTests/Services.cs diff --git a/Tests/NullabilityTestClasses.cs b/src/Tests/NullabilityTestClasses.cs similarity index 100% rename from Tests/NullabilityTestClasses.cs rename to src/Tests/NullabilityTestClasses.cs diff --git a/Tests/Tests.csproj b/src/Tests/Tests.csproj similarity index 94% rename from Tests/Tests.csproj rename to src/Tests/Tests.csproj index a518743..3132e21 100644 --- a/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -28,7 +28,7 @@ - + From 98b97eda0b4f9d7833cefdb44bf57f0a03e61996 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:34:03 -0400 Subject: [PATCH 10/31] Update --- GraphQL.DI.sln | 2 +- src/GraphQL.DI/{GraphQL.DI.csproj => Shane32.GraphQL.DI.csproj} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/GraphQL.DI/{GraphQL.DI.csproj => Shane32.GraphQL.DI.csproj} (100%) diff --git a/GraphQL.DI.sln b/GraphQL.DI.sln index e0ee951..6ab94d2 100644 --- a/GraphQL.DI.sln +++ b/GraphQL.DI.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30611.23 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.DI", "src\GraphQL.DI\GraphQL.DI.csproj", "{72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shane32.GraphQL.DI", "src\GraphQL.DI\Shane32.GraphQL.DI.csproj", "{72C179A6-53BF-48BC-BFE0-BD8CA2618AF6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{B194B3FB-53C8-4C5D-ABC3-EAB6A52C674D}" ProjectSection(SolutionItems) = preProject diff --git a/src/GraphQL.DI/GraphQL.DI.csproj b/src/GraphQL.DI/Shane32.GraphQL.DI.csproj similarity index 100% rename from src/GraphQL.DI/GraphQL.DI.csproj rename to src/GraphQL.DI/Shane32.GraphQL.DI.csproj From 77019c3f0e7059a3dc0b2222f3c838dbfa0f3b2b Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:35:25 -0400 Subject: [PATCH 11/31] Fix reference --- src/Tests/Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 3132e21..efd9a61 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -28,7 +28,7 @@ - + From 9747f93251d8d1411a10758a093af0d219631174 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 15:37:44 -0400 Subject: [PATCH 12/31] Update test.yml --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a4d34c..155c916 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] - run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[GraphQL.DI]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[Shane32.GraphQL.DI]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== - name: Convert coverage report to clover & htmlsummary format if: ${{ matrix.os == 'ubuntu-latest' }} From c94cb9bf61b2d232b34d14ebc6eb5119b47dde7c Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 15:55:45 -0400 Subject: [PATCH 13/31] Update --- src/Tests/Tests.csproj | 4 +- ubuntu-latest.lcov.info | 904 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 906 insertions(+), 2 deletions(-) create mode 100644 ubuntu-latest.lcov.info diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index efd9a61..118d0fb 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -21,9 +21,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ubuntu-latest.lcov.info b/ubuntu-latest.lcov.info new file mode 100644 index 0000000..64fc027 --- /dev/null +++ b/ubuntu-latest.lcov.info @@ -0,0 +1,904 @@ +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\ConcurrentAttribute.cs +FN:24,System.Boolean GraphQL.DI.ConcurrentAttribute::get_Concurrent() +FNDA:13,System.Boolean GraphQL.DI.ConcurrentAttribute::get_Concurrent() +DA:25,13 +FN:30,System.Boolean GraphQL.DI.ConcurrentAttribute::get_CreateNewScope() +FNDA:19,System.Boolean GraphQL.DI.ConcurrentAttribute::get_CreateNewScope() +DA:31,19 +FN:14,System.Void GraphQL.DI.ConcurrentAttribute::.ctor() +FNDA:6,System.Void GraphQL.DI.ConcurrentAttribute::.ctor() +DA:15,6 +FN:19,System.Void GraphQL.DI.ConcurrentAttribute::.ctor(System.Boolean) +FNDA:20,System.Void GraphQL.DI.ConcurrentAttribute::.ctor(System.Boolean) +DA:20,20 +LF:4 +LH:4 +BRF:0 +BRH:0 +FNF:4 +FNH:4 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIDocumentExecuter.cs +FN:67,GraphQL.Execution.IExecutionStrategy GraphQL.DI.DIDocumentExecuter::SelectExecutionStrategy(GraphQL.Execution.ExecutionContext) +FNDA:0,GraphQL.Execution.IExecutionStrategy GraphQL.DI.DIDocumentExecuter::SelectExecutionStrategy(GraphQL.Execution.ExecutionContext) +DA:68,0 +DA:69,0 +DA:72,0 +DA:75,0 +DA:78,0 +DA:81,0 +DA:83,0 +BRDA:69,16,1,0 +BRDA:69,16,2,0 +BRDA:69,16,3,0 +BRDA:78,60,0,0 +BRDA:78,60,1,0 +BRDA:69,16,0,0 +FN:21,System.Void GraphQL.DI.DIDocumentExecuter::.ctor() +FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor() +DA:22,0 +DA:26,0 +DA:31,0 +DA:32,0 +DA:33,0 +FN:37,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(GraphQL.Execution.IExecutionStrategy) +FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(GraphQL.Execution.IExecutionStrategy) +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +FN:48,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider) +FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider) +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +BRDA:49,21,0,0 +BRDA:49,21,1,0 +BRDA:49,41,0,0 +BRDA:49,41,1,0 +BRDA:49,56,0,0 +BRDA:49,56,1,0 +BRDA:49,71,0,0 +BRDA:49,71,1,0 +FN:60,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider,GraphQL.Execution.IExecutionStrategy) +FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider,GraphQL.Execution.IExecutionStrategy) +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +LF:26 +LH:0 +BRF:14 +BRH:0 +FNF:5 +FNH:0 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIExecutionStrategy.cs +FN:34,System.Void GraphQL.DI.DIExecutionStrategy::g__DICompleteNode|1_1(GraphQL.Execution.ExecutionNode,GraphQL.DI.DIExecutionStrategy/<>c__DisplayClass1_0&) +FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy::g__DICompleteNode|1_1(GraphQL.Execution.ExecutionNode,GraphQL.DI.DIExecutionStrategy/<>c__DisplayClass1_0&) +DA:35,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:45,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +BRDA:39,17,0,0 +BRDA:39,17,1,0 +BRDA:43,53,0,0 +BRDA:45,160,1,0 +BRDA:47,101,0,0 +BRDA:47,101,1,0 +BRDA:47,117,0,0 +BRDA:47,117,1,0 +BRDA:45,160,0,0 +BRDA:43,53,1,0 +FN:16,System.Void GraphQL.DI.DIExecutionStrategy::.cctor() +FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy::.cctor() +DA:17,0 +FN:21,System.Void GraphQL.DI.DIExecutionStrategy/<>c/<b__1_0>d::MoveNext() +FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy/<>c/<b__1_0>d::MoveNext() +DA:22,0 +FN:20,System.Void GraphQL.DI.DIExecutionStrategy/d__1::MoveNext() +FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy/d__1::MoveNext() +DA:21,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:58,0 +DA:60,0 +DA:62,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:76,0 +DA:78,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:87,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:100,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:107,0 +DA:110,0 +DA:111,0 +DA:115,0 +DA:117,0 +DA:118,0 +DA:125,0 +DA:126,0 +DA:127,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:131,0 +DA:132,0 +DA:133,0 +BRDA:30,216,0,0 +BRDA:30,216,1,0 +BRDA:31,248,0,0 +BRDA:31,248,1,0 +BRDA:60,578,1,0 +BRDA:65,338,0,0 +BRDA:65,338,1,0 +BRDA:60,550,0,0 +BRDA:60,550,1,0 +BRDA:76,915,1,0 +BRDA:81,655,0,0 +BRDA:81,655,1,0 +BRDA:60,578,0,0 +BRDA:76,879,0,0 +BRDA:76,887,0,0 +BRDA:76,879,1,0 +BRDA:76,887,1,0 +BRDA:76,915,0,0 +BRDA:94,938,0,0 +BRDA:94,938,1,0 +BRDA:98,1123,0,0 +BRDA:103,1304,0,0 +BRDA:103,1304,1,0 +BRDA:98,1123,1,0 +BRDA:115,1488,0,0 +BRDA:115,1506,0,0 +BRDA:115,1488,1,0 +BRDA:115,1506,1,0 +BRDA:115,1529,0,0 +BRDA:117,1558,0,0 +BRDA:125,1788,1,0 +BRDA:117,1558,1,0 +BRDA:125,1788,0,0 +BRDA:115,1529,1,0 +LF:75 +LH:0 +BRF:44 +BRH:0 +FNF:4 +FNH:0 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIFieldType.cs +FN:10,System.Boolean GraphQL.DI.DIFieldType::get_Concurrent() +FNDA:300,System.Boolean GraphQL.DI.DIFieldType::get_Concurrent() +DA:11,300 +LF:1 +LH:1 +BRF:0 +BRH:0 +FNF:1 +FNH:1 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIObjectGraphType.cs +FN:75,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultConcurrent() +FNDA:178,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultConcurrent() +DA:76,178 +FN:80,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultCreateScope() +FNDA:178,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultCreateScope() +DA:81,178 +FN:87,System.Collections.Generic.List`1 GraphQL.DI.DIObjectGraphType`2::CreateFieldTypeList() +FNDA:54,System.Collections.Generic.List`1 GraphQL.DI.DIObjectGraphType`2::CreateFieldTypeList() +DA:88,54 +DA:90,54 +DA:91,54 +DA:92,547 +DA:93,129 +DA:94,127 +DA:95,127 +DA:96,127 +DA:97,52 +DA:98,52 +BRDA:92,74,1,129 +BRDA:94,56,0,127 +BRDA:94,56,1,127 +BRDA:92,74,0,52 +FN:104,System.Collections.Generic.IEnumerable`1 GraphQL.DI.DIObjectGraphType`2::GetMethodsToProcess() +FNDA:53,System.Collections.Generic.IEnumerable`1 GraphQL.DI.DIObjectGraphType`2::GetMethodsToProcess() +DA:105,53 +DA:106,311 +DA:107,53 +BRDA:106,24,0,44 +BRDA:106,24,1,53 +FN:112,GraphQL.DI.DIFieldType GraphQL.DI.DIObjectGraphType`2::ProcessMethod(System.Reflection.MethodInfo) +FNDA:129,GraphQL.DI.DIFieldType GraphQL.DI.DIObjectGraphType`2::ProcessMethod(System.Reflection.MethodInfo) +DA:113,129 +DA:115,129 +DA:116,129 +DA:117,130 +DA:118,1 +DA:119,129 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,128 +DA:124,129 +DA:125,0 +DA:128,129 +DA:129,0 +DA:133,129 +DA:134,129 +DA:135,129 +DA:136,129 +DA:137,129 +DA:138,129 +DA:139,451 +DA:140,22 +DA:141,20 +DA:142,20 +DA:143,8 +DA:145,20 +DA:146,20 +DA:148,127 +DA:151,162 +DA:154,35 +DA:155,127 +DA:157,92 +DA:159,92 +DA:160,92 +DA:164,132 +DA:166,5 +DA:168,5 +DA:169,127 +DA:170,122 +DA:171,122 +DA:172,122 +DA:173,127 +DA:174,5 +DA:175,5 +DA:176,5 +DA:178,126 +DA:180,4 +DA:182,8 +DA:186,4 +DA:187,0 +DA:189,0 +DA:190,0 +DA:191,4 +DA:193,118 +DA:194,118 +DA:196,118 +DA:197,118 +DA:198,122 +DA:199,127 +DA:202,127 +DA:204,127 +DA:205,127 +DA:207,253 +DA:209,126 +DA:210,174 +DA:211,48 +DA:212,126 +DA:213,78 +DA:214,78 +DA:215,126 +DA:217,127 +DA:219,127 +DA:221,127 +DA:222,127 +DA:223,127 +DA:224,127 +DA:225,127 +DA:226,127 +DA:227,127 +DA:228,127 +DA:229,127 +DA:231,0 +DA:232,0 +DA:234,127 +DA:237,127 +BRDA:117,23,0,1 +BRDA:117,23,1,128 +BRDA:120,48,0,0 +BRDA:120,61,0,0 +BRDA:120,48,1,128 +BRDA:120,61,1,128 +BRDA:120,96,0,0 +BRDA:120,96,1,128 +BRDA:124,134,0,0 +BRDA:124,134,1,129 +BRDA:128,165,0,129 +BRDA:128,165,1,0 +BRDA:128,195,0,0 +BRDA:128,195,1,129 +BRDA:139,331,1,22 +BRDA:142,297,0,8 +BRDA:142,297,1,20 +BRDA:139,331,0,127 +BRDA:151,366,0,35 +BRDA:151,366,1,92 +BRDA:164,418,0,48 +BRDA:164,426,0,11 +BRDA:164,418,1,116 +BRDA:164,426,1,116 +BRDA:164,440,0,5 +BRDA:164,440,1,122 +BRDA:173,494,0,5 +BRDA:173,494,1,122 +BRDA:178,525,0,4 +BRDA:182,537,0,4 +BRDA:182,537,1,0 +BRDA:178,525,1,118 +BRDA:205,599,0,126 +BRDA:205,599,1,1 +BRDA:207,625,0,126 +BRDA:210,648,0,96 +BRDA:210,648,1,30 +BRDA:210,683,0,48 +BRDA:210,683,1,78 +BRDA:207,625,1,127 +BRDA:217,738,0,126 +BRDA:217,738,1,1 +BRDA:219,758,0,126 +BRDA:219,758,1,1 +BRDA:231,902,1,0 +BRDA:231,902,0,127 +FN:242,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo) +FNDA:170,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo) +DA:243,170 +DA:244,170 +DA:245,14 +DA:246,156 +DA:247,15 +DA:248,141 +DA:249,10 +DA:251,131 +DA:254,131 +DA:255,131 +DA:256,151 +DA:257,151 +DA:258,151 +DA:259,149 +DA:260,18 +DA:261,18 +DA:264,131 +DA:265,154 +DA:266,154 +DA:267,154 +DA:268,144 +DA:269,13 +DA:270,13 +DA:273,131 +DA:274,138 +DA:275,138 +DA:276,138 +DA:277,138 +DA:278,134 +DA:279,3 +DA:280,3 +DA:282,131 +DA:283,131 +DA:284,131 +DA:285,131 +DA:306,170 +BRDA:244,12,0,14 +BRDA:244,12,1,156 +BRDA:246,35,0,15 +BRDA:246,35,1,141 +BRDA:248,60,0,10 +BRDA:249,73,0,5 +BRDA:249,73,1,5 +BRDA:248,60,1,131 +BRDA:255,138,0,29 +BRDA:255,138,1,131 +BRDA:259,177,0,18 +BRDA:259,177,1,131 +BRDA:264,226,0,29 +BRDA:264,226,1,131 +BRDA:268,265,0,13 +BRDA:268,265,1,131 +BRDA:273,319,0,29 +BRDA:273,319,1,131 +BRDA:278,351,0,7 +BRDA:278,351,1,124 +BRDA:278,396,0,3 +BRDA:278,396,1,131 +BRDA:282,436,0,124 +BRDA:282,436,1,7 +BRDA:256,21,0,18 +BRDA:256,35,0,18 +BRDA:256,21,1,2 +BRDA:256,35,1,2 +BRDA:265,21,0,13 +BRDA:265,35,0,13 +BRDA:265,21,1,10 +BRDA:265,35,1,10 +BRDA:274,21,0,7 +BRDA:274,35,0,7 +BRDA:274,72,0,4 +BRDA:274,72,1,3 +BRDA:274,21,1,0 +BRDA:274,35,1,0 +FN:318,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo,System.Reflection.ParameterInfo) +FNDA:23,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo,System.Reflection.ParameterInfo) +DA:319,23 +DA:320,23 +DA:321,3 +DA:322,20 +DA:323,2 +DA:324,18 +DA:325,0 +DA:326,18 +DA:327,6 +DA:329,12 +DA:332,12 +DA:333,12 +DA:334,18 +DA:335,18 +DA:336,18 +DA:337,18 +DA:338,6 +DA:339,6 +DA:342,12 +DA:343,16 +DA:344,16 +DA:345,16 +DA:346,16 +DA:347,4 +DA:348,4 +DA:351,12 +DA:352,16 +DA:353,16 +DA:354,16 +DA:355,16 +DA:356,14 +DA:357,2 +DA:358,2 +DA:360,12 +DA:361,12 +DA:362,12 +DA:363,12 +DA:378,23 +BRDA:320,12,0,3 +BRDA:320,12,1,20 +BRDA:322,35,0,2 +BRDA:322,35,1,18 +BRDA:324,58,0,0 +BRDA:324,58,1,18 +BRDA:326,83,0,6 +BRDA:327,96,0,3 +BRDA:327,96,1,3 +BRDA:326,83,1,12 +BRDA:333,161,0,3 +BRDA:333,161,1,12 +BRDA:337,200,0,6 +BRDA:337,200,1,12 +BRDA:342,249,0,3 +BRDA:342,249,1,12 +BRDA:346,288,0,4 +BRDA:346,288,1,12 +BRDA:351,337,0,3 +BRDA:351,337,1,12 +BRDA:356,369,0,2 +BRDA:356,369,1,10 +BRDA:356,414,0,2 +BRDA:356,414,1,12 +BRDA:360,454,0,10 +BRDA:360,454,1,2 +BRDA:334,21,0,6 +BRDA:334,35,0,6 +BRDA:334,21,1,0 +BRDA:334,35,1,0 +BRDA:343,21,0,4 +BRDA:343,35,0,4 +BRDA:343,21,1,0 +BRDA:343,35,1,0 +BRDA:352,21,0,2 +BRDA:352,35,0,2 +BRDA:352,72,0,0 +BRDA:352,72,1,2 +BRDA:352,21,1,2 +BRDA:352,35,1,2 +FN:383,System.Type GraphQL.DI.DIObjectGraphType`2::InferInputGraphType(System.Type,System.Boolean) +FNDA:7,System.Type GraphQL.DI.DIObjectGraphType`2::InferInputGraphType(System.Type,System.Boolean) +DA:384,7 +DA:385,7 +DA:386,7 +FN:391,System.Type GraphQL.DI.DIObjectGraphType`2::InferOutputGraphType(System.Type,System.Boolean) +FNDA:126,System.Type GraphQL.DI.DIObjectGraphType`2::InferOutputGraphType(System.Type,System.Boolean) +DA:392,126 +DA:393,126 +DA:394,126 +FN:401,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetInstanceExpression(System.Linq.Expressions.ParameterExpression) +FNDA:92,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetInstanceExpression(System.Linq.Expressions.ParameterExpression) +DA:402,92 +DA:403,92 +DA:404,92 +FN:411,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceProviderExpression(System.Linq.Expressions.ParameterExpression) +FNDA:101,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceProviderExpression(System.Linq.Expressions.ParameterExpression) +DA:412,101 +DA:414,101 +DA:415,101 +FN:422,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceExpression(System.Linq.Expressions.ParameterExpression,System.Type) +FNDA:96,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceExpression(System.Linq.Expressions.ParameterExpression,System.Type) +DA:423,96 +DA:425,96 +DA:426,96 +DA:427,96 +DA:428,96 +DA:429,96 +DA:430,96 +BRDA:426,11,0,0 +BRDA:426,11,1,96 +FN:436,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateUnscopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) +FNDA:123,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateUnscopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) +DA:437,123 +DA:438,228 +DA:439,123 +DA:440,123 +DA:441,123 +BRDA:438,19,0,33 +BRDA:438,19,1,123 +FN:448,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateScopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) +FNDA:4,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateScopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) +DA:449,4 +DA:451,8 +DA:452,8 +DA:453,0 +DA:454,0 +DA:455,0 +DA:456,4 +DA:457,4 +DA:458,4 +BRDA:451,24,0,4 +BRDA:452,50,0,4 +BRDA:452,50,1,4 +BRDA:451,24,1,0 +BRDA:454,103,0,0 +BRDA:454,103,1,0 +FN:460,System.Type GraphQL.DI.DIObjectGraphType`2::GetTaskType(System.Type) +FNDA:4,System.Type GraphQL.DI.DIObjectGraphType`2::GetTaskType(System.Type) +DA:461,4 +DA:462,8 +DA:463,4 +DA:464,4 +DA:465,0 +DA:466,0 +DA:467,0 +DA:468,4 +BRDA:462,69,1,4 +BRDA:463,10,0,4 +BRDA:463,10,1,0 +BRDA:463,38,0,4 +BRDA:463,38,1,0 +BRDA:462,69,0,0 +FN:476,GraphQL.Types.QueryArgument GraphQL.DI.DIObjectGraphType`2::ProcessParameter(System.Reflection.MethodInfo,System.Reflection.ParameterInfo,System.Linq.Expressions.ParameterExpression,System.Boolean&,System.Linq.Expressions.Expression&) +FNDA:22,GraphQL.Types.QueryArgument GraphQL.DI.DIObjectGraphType`2::ProcessParameter(System.Reflection.MethodInfo,System.Reflection.ParameterInfo,System.Linq.Expressions.ParameterExpression,System.Boolean&,System.Linq.Expressions.Expression&) +DA:477,22 +DA:478,22 +DA:480,23 +DA:483,1 +DA:485,1 +DA:487,0 +DA:489,0 +DA:491,0 +DA:493,23 +DA:495,2 +DA:496,2 +DA:497,1 +DA:499,1 +DA:501,1 +DA:503,1 +DA:505,21 +DA:507,2 +DA:508,1 +DA:511,1 +DA:513,1 +DA:515,22 +DA:518,5 +DA:520,5 +DA:522,5 +DA:524,16 +DA:527,4 +DA:529,4 +DA:531,4 +DA:534,8 +DA:535,0 +DA:538,0 +DA:540,0 +DA:546,8 +DA:547,8 +DA:549,15 +DA:551,7 +DA:552,7 +DA:553,7 +DA:556,8 +DA:557,8 +DA:558,8 +DA:559,8 +DA:561,0 +DA:562,0 +DA:565,8 +DA:566,0 +DA:567,0 +DA:568,0 +DA:569,3 +DA:570,3 +DA:573,8 +DA:575,8 +DA:578,8 +DA:579,20 +BRDA:480,30,0,1 +BRDA:480,30,1,21 +BRDA:487,70,0,0 +BRDA:487,70,1,21 +BRDA:493,106,0,3 +BRDA:493,106,1,18 +BRDA:493,141,0,2 +BRDA:496,183,0,1 +BRDA:496,183,1,1 +BRDA:493,141,1,19 +BRDA:505,262,0,2 +BRDA:507,293,0,1 +BRDA:507,293,1,1 +BRDA:505,262,1,17 +BRDA:515,375,0,5 +BRDA:515,375,1,12 +BRDA:524,413,0,4 +BRDA:524,413,1,8 +BRDA:535,452,0,1 +BRDA:535,452,1,7 +BRDA:535,470,0,0 +BRDA:538,486,0,0 +BRDA:538,486,1,0 +BRDA:535,470,1,8 +BRDA:547,530,0,7 +BRDA:547,530,1,1 +BRDA:549,553,0,7 +BRDA:549,553,1,8 +BRDA:556,590,0,7 +BRDA:556,590,1,1 +BRDA:556,602,0,7 +BRDA:556,602,1,8 +BRDA:556,625,0,7 +BRDA:556,625,1,1 +BRDA:561,701,1,0 +BRDA:561,701,0,8 +BRDA:566,731,0,0 +BRDA:566,731,1,8 +BRDA:568,760,0,3 +BRDA:568,760,1,8 +FN:287,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|18_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass18_0&) +FNDA:256,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|18_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass18_0&) +DA:288,256 +DA:289,256 +DA:290,256 +DA:291,18 +DA:292,238 +DA:293,18 +DA:294,220 +DA:295,14 +DA:296,331 +DA:297,125 +DA:298,125 +DA:300,81 +DA:301,9 +DA:302,72 +DA:303,0 +DA:304,72 +DA:305,256 +BRDA:289,7,0,111 +BRDA:289,7,1,145 +BRDA:290,37,0,18 +BRDA:290,37,1,238 +BRDA:292,54,0,18 +BRDA:292,54,1,220 +BRDA:294,69,0,0 +BRDA:294,69,1,220 +BRDA:294,85,0,220 +BRDA:294,93,0,220 +BRDA:294,93,1,0 +BRDA:294,85,1,0 +BRDA:294,114,0,14 +BRDA:294,114,1,206 +BRDA:296,139,0,131 +BRDA:296,139,1,75 +BRDA:296,164,0,125 +BRDA:296,164,1,81 +BRDA:300,222,0,9 +BRDA:300,222,1,72 +BRDA:302,241,0,0 +BRDA:302,241,1,72 +FN:365,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|20_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass20_0&) +FNDA:12,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|20_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass20_0&) +DA:366,12 +DA:367,12 +DA:368,12 +DA:369,0 +DA:370,12 +DA:371,0 +DA:372,12 +DA:373,4 +DA:374,8 +DA:375,0 +DA:376,8 +DA:377,12 +BRDA:367,7,0,12 +BRDA:367,7,1,0 +BRDA:368,37,0,0 +BRDA:368,37,1,12 +BRDA:370,51,0,0 +BRDA:370,51,1,12 +BRDA:372,63,0,0 +BRDA:372,63,1,12 +BRDA:372,79,0,12 +BRDA:372,87,0,12 +BRDA:372,87,1,0 +BRDA:372,79,1,0 +BRDA:372,108,0,4 +BRDA:372,108,1,8 +BRDA:374,127,0,0 +BRDA:374,127,1,8 +FN:33,System.Void GraphQL.DI.DIObjectGraphType`2::.ctor() +FNDA:54,System.Void GraphQL.DI.DIObjectGraphType`2::.ctor() +DA:34,54 +DA:35,54 +DA:36,54 +DA:38,54 +DA:39,54 +DA:40,1 +DA:42,54 +DA:43,54 +DA:44,1 +DA:45,54 +DA:46,54 +DA:47,1 +DA:49,164 +DA:50,1 +DA:52,54 +DA:53,56 +DA:54,2 +DA:55,2 +DA:56,2 +DA:59,54 +DA:60,52 +DA:61,410 +DA:62,127 +DA:63,52 +DA:432,54 +DA:443,54 +DA:444,54 +BRDA:39,81,0,1 +BRDA:39,81,1,54 +BRDA:43,111,0,1 +BRDA:43,111,1,54 +BRDA:46,141,0,1 +BRDA:46,141,1,54 +BRDA:49,214,1,1 +BRDA:49,214,0,54 +BRDA:53,248,0,2 +BRDA:53,248,1,54 +BRDA:60,291,0,52 +BRDA:61,330,1,127 +BRDA:61,330,0,52 +BRDA:60,291,1,52 +FN:65,System.Void GraphQL.DI.DIObjectGraphType`2::.cctor() +FNDA:147,System.Void GraphQL.DI.DIObjectGraphType`2::.cctor() +DA:66,147 +DA:67,210 +DA:68,210 +DA:69,21 +DA:70,21 +DA:71,21 +BRDA:66,16,0,42 +BRDA:66,16,1,84 +BRDA:67,16,0,42 +BRDA:67,27,0,42 +BRDA:67,16,1,147 +BRDA:67,27,1,147 +BRDA:68,16,0,42 +BRDA:68,16,1,147 +LF:331 +LH:299 +BRF:246 +BRH:206 +FNF:20 +FNH:20 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\GraphTypeAttribute.cs +FN:22,System.Type GraphQL.DI.GraphTypeAttribute::get_Type() +FNDA:2,System.Type GraphQL.DI.GraphTypeAttribute::get_Type() +DA:23,2 +FN:14,System.Void GraphQL.DI.GraphTypeAttribute::.ctor(System.Type) +FNDA:2,System.Void GraphQL.DI.GraphTypeAttribute::.ctor(System.Type) +DA:15,2 +DA:16,2 +DA:17,2 +DA:18,2 +LF:5 +LH:5 +BRF:0 +BRH:0 +FNF:2 +FNH:2 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\MetadataAttribute.cs +FN:20,System.String GraphQL.DI.MetadataAttribute::get_Key() +FNDA:2,System.String GraphQL.DI.MetadataAttribute::get_Key() +DA:21,2 +FN:25,System.Object GraphQL.DI.MetadataAttribute::get_Value() +FNDA:2,System.Object GraphQL.DI.MetadataAttribute::get_Value() +DA:26,2 +FN:11,System.Void GraphQL.DI.MetadataAttribute::.ctor(System.String,System.Object) +FNDA:1,System.Void GraphQL.DI.MetadataAttribute::.ctor(System.String,System.Object) +DA:12,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,1 +LF:7 +LH:7 +BRF:0 +BRH:0 +FNF:3 +FNH:3 +end_of_record +SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\NameAttribute.cs +FN:21,System.String GraphQL.DI.NameAttribute::get_Name() +FNDA:4,System.String GraphQL.DI.NameAttribute::get_Name() +DA:22,4 +FN:13,System.Void GraphQL.DI.NameAttribute::.ctor(System.String) +FNDA:3,System.Void GraphQL.DI.NameAttribute::.ctor(System.String) +DA:14,3 +DA:15,3 +DA:16,3 +DA:17,3 +LF:5 +LH:5 +BRF:0 +BRH:0 +FNF:2 +FNH:2 +end_of_record \ No newline at end of file From 6bc6865f33d3a4ee3fc1484c0311ba378d018f53 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 16:15:26 -0400 Subject: [PATCH 14/31] Update --- ubuntu-latest.lcov.info | 904 ---------------------------------------- 1 file changed, 904 deletions(-) delete mode 100644 ubuntu-latest.lcov.info diff --git a/ubuntu-latest.lcov.info b/ubuntu-latest.lcov.info deleted file mode 100644 index 64fc027..0000000 --- a/ubuntu-latest.lcov.info +++ /dev/null @@ -1,904 +0,0 @@ -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\ConcurrentAttribute.cs -FN:24,System.Boolean GraphQL.DI.ConcurrentAttribute::get_Concurrent() -FNDA:13,System.Boolean GraphQL.DI.ConcurrentAttribute::get_Concurrent() -DA:25,13 -FN:30,System.Boolean GraphQL.DI.ConcurrentAttribute::get_CreateNewScope() -FNDA:19,System.Boolean GraphQL.DI.ConcurrentAttribute::get_CreateNewScope() -DA:31,19 -FN:14,System.Void GraphQL.DI.ConcurrentAttribute::.ctor() -FNDA:6,System.Void GraphQL.DI.ConcurrentAttribute::.ctor() -DA:15,6 -FN:19,System.Void GraphQL.DI.ConcurrentAttribute::.ctor(System.Boolean) -FNDA:20,System.Void GraphQL.DI.ConcurrentAttribute::.ctor(System.Boolean) -DA:20,20 -LF:4 -LH:4 -BRF:0 -BRH:0 -FNF:4 -FNH:4 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIDocumentExecuter.cs -FN:67,GraphQL.Execution.IExecutionStrategy GraphQL.DI.DIDocumentExecuter::SelectExecutionStrategy(GraphQL.Execution.ExecutionContext) -FNDA:0,GraphQL.Execution.IExecutionStrategy GraphQL.DI.DIDocumentExecuter::SelectExecutionStrategy(GraphQL.Execution.ExecutionContext) -DA:68,0 -DA:69,0 -DA:72,0 -DA:75,0 -DA:78,0 -DA:81,0 -DA:83,0 -BRDA:69,16,1,0 -BRDA:69,16,2,0 -BRDA:69,16,3,0 -BRDA:78,60,0,0 -BRDA:78,60,1,0 -BRDA:69,16,0,0 -FN:21,System.Void GraphQL.DI.DIDocumentExecuter::.ctor() -FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor() -DA:22,0 -DA:26,0 -DA:31,0 -DA:32,0 -DA:33,0 -FN:37,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(GraphQL.Execution.IExecutionStrategy) -FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(GraphQL.Execution.IExecutionStrategy) -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -FN:48,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider) -FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider) -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -BRDA:49,21,0,0 -BRDA:49,21,1,0 -BRDA:49,41,0,0 -BRDA:49,41,1,0 -BRDA:49,56,0,0 -BRDA:49,56,1,0 -BRDA:49,71,0,0 -BRDA:49,71,1,0 -FN:60,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider,GraphQL.Execution.IExecutionStrategy) -FNDA:0,System.Void GraphQL.DI.DIDocumentExecuter::.ctor(System.IServiceProvider,GraphQL.Execution.IExecutionStrategy) -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -LF:26 -LH:0 -BRF:14 -BRH:0 -FNF:5 -FNH:0 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIExecutionStrategy.cs -FN:34,System.Void GraphQL.DI.DIExecutionStrategy::g__DICompleteNode|1_1(GraphQL.Execution.ExecutionNode,GraphQL.DI.DIExecutionStrategy/<>c__DisplayClass1_0&) -FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy::g__DICompleteNode|1_1(GraphQL.Execution.ExecutionNode,GraphQL.DI.DIExecutionStrategy/<>c__DisplayClass1_0&) -DA:35,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:45,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -BRDA:39,17,0,0 -BRDA:39,17,1,0 -BRDA:43,53,0,0 -BRDA:45,160,1,0 -BRDA:47,101,0,0 -BRDA:47,101,1,0 -BRDA:47,117,0,0 -BRDA:47,117,1,0 -BRDA:45,160,0,0 -BRDA:43,53,1,0 -FN:16,System.Void GraphQL.DI.DIExecutionStrategy::.cctor() -FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy::.cctor() -DA:17,0 -FN:21,System.Void GraphQL.DI.DIExecutionStrategy/<>c/<b__1_0>d::MoveNext() -FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy/<>c/<b__1_0>d::MoveNext() -DA:22,0 -FN:20,System.Void GraphQL.DI.DIExecutionStrategy/d__1::MoveNext() -FNDA:0,System.Void GraphQL.DI.DIExecutionStrategy/d__1::MoveNext() -DA:21,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:76,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -BRDA:30,216,0,0 -BRDA:30,216,1,0 -BRDA:31,248,0,0 -BRDA:31,248,1,0 -BRDA:60,578,1,0 -BRDA:65,338,0,0 -BRDA:65,338,1,0 -BRDA:60,550,0,0 -BRDA:60,550,1,0 -BRDA:76,915,1,0 -BRDA:81,655,0,0 -BRDA:81,655,1,0 -BRDA:60,578,0,0 -BRDA:76,879,0,0 -BRDA:76,887,0,0 -BRDA:76,879,1,0 -BRDA:76,887,1,0 -BRDA:76,915,0,0 -BRDA:94,938,0,0 -BRDA:94,938,1,0 -BRDA:98,1123,0,0 -BRDA:103,1304,0,0 -BRDA:103,1304,1,0 -BRDA:98,1123,1,0 -BRDA:115,1488,0,0 -BRDA:115,1506,0,0 -BRDA:115,1488,1,0 -BRDA:115,1506,1,0 -BRDA:115,1529,0,0 -BRDA:117,1558,0,0 -BRDA:125,1788,1,0 -BRDA:117,1558,1,0 -BRDA:125,1788,0,0 -BRDA:115,1529,1,0 -LF:75 -LH:0 -BRF:44 -BRH:0 -FNF:4 -FNH:0 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIFieldType.cs -FN:10,System.Boolean GraphQL.DI.DIFieldType::get_Concurrent() -FNDA:300,System.Boolean GraphQL.DI.DIFieldType::get_Concurrent() -DA:11,300 -LF:1 -LH:1 -BRF:0 -BRH:0 -FNF:1 -FNH:1 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\DIObjectGraphType.cs -FN:75,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultConcurrent() -FNDA:178,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultConcurrent() -DA:76,178 -FN:80,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultCreateScope() -FNDA:178,System.Boolean GraphQL.DI.DIObjectGraphType`2::get_DefaultCreateScope() -DA:81,178 -FN:87,System.Collections.Generic.List`1 GraphQL.DI.DIObjectGraphType`2::CreateFieldTypeList() -FNDA:54,System.Collections.Generic.List`1 GraphQL.DI.DIObjectGraphType`2::CreateFieldTypeList() -DA:88,54 -DA:90,54 -DA:91,54 -DA:92,547 -DA:93,129 -DA:94,127 -DA:95,127 -DA:96,127 -DA:97,52 -DA:98,52 -BRDA:92,74,1,129 -BRDA:94,56,0,127 -BRDA:94,56,1,127 -BRDA:92,74,0,52 -FN:104,System.Collections.Generic.IEnumerable`1 GraphQL.DI.DIObjectGraphType`2::GetMethodsToProcess() -FNDA:53,System.Collections.Generic.IEnumerable`1 GraphQL.DI.DIObjectGraphType`2::GetMethodsToProcess() -DA:105,53 -DA:106,311 -DA:107,53 -BRDA:106,24,0,44 -BRDA:106,24,1,53 -FN:112,GraphQL.DI.DIFieldType GraphQL.DI.DIObjectGraphType`2::ProcessMethod(System.Reflection.MethodInfo) -FNDA:129,GraphQL.DI.DIFieldType GraphQL.DI.DIObjectGraphType`2::ProcessMethod(System.Reflection.MethodInfo) -DA:113,129 -DA:115,129 -DA:116,129 -DA:117,130 -DA:118,1 -DA:119,129 -DA:120,0 -DA:121,0 -DA:122,0 -DA:123,128 -DA:124,129 -DA:125,0 -DA:128,129 -DA:129,0 -DA:133,129 -DA:134,129 -DA:135,129 -DA:136,129 -DA:137,129 -DA:138,129 -DA:139,451 -DA:140,22 -DA:141,20 -DA:142,20 -DA:143,8 -DA:145,20 -DA:146,20 -DA:148,127 -DA:151,162 -DA:154,35 -DA:155,127 -DA:157,92 -DA:159,92 -DA:160,92 -DA:164,132 -DA:166,5 -DA:168,5 -DA:169,127 -DA:170,122 -DA:171,122 -DA:172,122 -DA:173,127 -DA:174,5 -DA:175,5 -DA:176,5 -DA:178,126 -DA:180,4 -DA:182,8 -DA:186,4 -DA:187,0 -DA:189,0 -DA:190,0 -DA:191,4 -DA:193,118 -DA:194,118 -DA:196,118 -DA:197,118 -DA:198,122 -DA:199,127 -DA:202,127 -DA:204,127 -DA:205,127 -DA:207,253 -DA:209,126 -DA:210,174 -DA:211,48 -DA:212,126 -DA:213,78 -DA:214,78 -DA:215,126 -DA:217,127 -DA:219,127 -DA:221,127 -DA:222,127 -DA:223,127 -DA:224,127 -DA:225,127 -DA:226,127 -DA:227,127 -DA:228,127 -DA:229,127 -DA:231,0 -DA:232,0 -DA:234,127 -DA:237,127 -BRDA:117,23,0,1 -BRDA:117,23,1,128 -BRDA:120,48,0,0 -BRDA:120,61,0,0 -BRDA:120,48,1,128 -BRDA:120,61,1,128 -BRDA:120,96,0,0 -BRDA:120,96,1,128 -BRDA:124,134,0,0 -BRDA:124,134,1,129 -BRDA:128,165,0,129 -BRDA:128,165,1,0 -BRDA:128,195,0,0 -BRDA:128,195,1,129 -BRDA:139,331,1,22 -BRDA:142,297,0,8 -BRDA:142,297,1,20 -BRDA:139,331,0,127 -BRDA:151,366,0,35 -BRDA:151,366,1,92 -BRDA:164,418,0,48 -BRDA:164,426,0,11 -BRDA:164,418,1,116 -BRDA:164,426,1,116 -BRDA:164,440,0,5 -BRDA:164,440,1,122 -BRDA:173,494,0,5 -BRDA:173,494,1,122 -BRDA:178,525,0,4 -BRDA:182,537,0,4 -BRDA:182,537,1,0 -BRDA:178,525,1,118 -BRDA:205,599,0,126 -BRDA:205,599,1,1 -BRDA:207,625,0,126 -BRDA:210,648,0,96 -BRDA:210,648,1,30 -BRDA:210,683,0,48 -BRDA:210,683,1,78 -BRDA:207,625,1,127 -BRDA:217,738,0,126 -BRDA:217,738,1,1 -BRDA:219,758,0,126 -BRDA:219,758,1,1 -BRDA:231,902,1,0 -BRDA:231,902,0,127 -FN:242,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo) -FNDA:170,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo) -DA:243,170 -DA:244,170 -DA:245,14 -DA:246,156 -DA:247,15 -DA:248,141 -DA:249,10 -DA:251,131 -DA:254,131 -DA:255,131 -DA:256,151 -DA:257,151 -DA:258,151 -DA:259,149 -DA:260,18 -DA:261,18 -DA:264,131 -DA:265,154 -DA:266,154 -DA:267,154 -DA:268,144 -DA:269,13 -DA:270,13 -DA:273,131 -DA:274,138 -DA:275,138 -DA:276,138 -DA:277,138 -DA:278,134 -DA:279,3 -DA:280,3 -DA:282,131 -DA:283,131 -DA:284,131 -DA:285,131 -DA:306,170 -BRDA:244,12,0,14 -BRDA:244,12,1,156 -BRDA:246,35,0,15 -BRDA:246,35,1,141 -BRDA:248,60,0,10 -BRDA:249,73,0,5 -BRDA:249,73,1,5 -BRDA:248,60,1,131 -BRDA:255,138,0,29 -BRDA:255,138,1,131 -BRDA:259,177,0,18 -BRDA:259,177,1,131 -BRDA:264,226,0,29 -BRDA:264,226,1,131 -BRDA:268,265,0,13 -BRDA:268,265,1,131 -BRDA:273,319,0,29 -BRDA:273,319,1,131 -BRDA:278,351,0,7 -BRDA:278,351,1,124 -BRDA:278,396,0,3 -BRDA:278,396,1,131 -BRDA:282,436,0,124 -BRDA:282,436,1,7 -BRDA:256,21,0,18 -BRDA:256,35,0,18 -BRDA:256,21,1,2 -BRDA:256,35,1,2 -BRDA:265,21,0,13 -BRDA:265,35,0,13 -BRDA:265,21,1,10 -BRDA:265,35,1,10 -BRDA:274,21,0,7 -BRDA:274,35,0,7 -BRDA:274,72,0,4 -BRDA:274,72,1,3 -BRDA:274,21,1,0 -BRDA:274,35,1,0 -FN:318,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo,System.Reflection.ParameterInfo) -FNDA:23,System.Boolean GraphQL.DI.DIObjectGraphType`2::GetNullability(System.Reflection.MethodInfo,System.Reflection.ParameterInfo) -DA:319,23 -DA:320,23 -DA:321,3 -DA:322,20 -DA:323,2 -DA:324,18 -DA:325,0 -DA:326,18 -DA:327,6 -DA:329,12 -DA:332,12 -DA:333,12 -DA:334,18 -DA:335,18 -DA:336,18 -DA:337,18 -DA:338,6 -DA:339,6 -DA:342,12 -DA:343,16 -DA:344,16 -DA:345,16 -DA:346,16 -DA:347,4 -DA:348,4 -DA:351,12 -DA:352,16 -DA:353,16 -DA:354,16 -DA:355,16 -DA:356,14 -DA:357,2 -DA:358,2 -DA:360,12 -DA:361,12 -DA:362,12 -DA:363,12 -DA:378,23 -BRDA:320,12,0,3 -BRDA:320,12,1,20 -BRDA:322,35,0,2 -BRDA:322,35,1,18 -BRDA:324,58,0,0 -BRDA:324,58,1,18 -BRDA:326,83,0,6 -BRDA:327,96,0,3 -BRDA:327,96,1,3 -BRDA:326,83,1,12 -BRDA:333,161,0,3 -BRDA:333,161,1,12 -BRDA:337,200,0,6 -BRDA:337,200,1,12 -BRDA:342,249,0,3 -BRDA:342,249,1,12 -BRDA:346,288,0,4 -BRDA:346,288,1,12 -BRDA:351,337,0,3 -BRDA:351,337,1,12 -BRDA:356,369,0,2 -BRDA:356,369,1,10 -BRDA:356,414,0,2 -BRDA:356,414,1,12 -BRDA:360,454,0,10 -BRDA:360,454,1,2 -BRDA:334,21,0,6 -BRDA:334,35,0,6 -BRDA:334,21,1,0 -BRDA:334,35,1,0 -BRDA:343,21,0,4 -BRDA:343,35,0,4 -BRDA:343,21,1,0 -BRDA:343,35,1,0 -BRDA:352,21,0,2 -BRDA:352,35,0,2 -BRDA:352,72,0,0 -BRDA:352,72,1,2 -BRDA:352,21,1,2 -BRDA:352,35,1,2 -FN:383,System.Type GraphQL.DI.DIObjectGraphType`2::InferInputGraphType(System.Type,System.Boolean) -FNDA:7,System.Type GraphQL.DI.DIObjectGraphType`2::InferInputGraphType(System.Type,System.Boolean) -DA:384,7 -DA:385,7 -DA:386,7 -FN:391,System.Type GraphQL.DI.DIObjectGraphType`2::InferOutputGraphType(System.Type,System.Boolean) -FNDA:126,System.Type GraphQL.DI.DIObjectGraphType`2::InferOutputGraphType(System.Type,System.Boolean) -DA:392,126 -DA:393,126 -DA:394,126 -FN:401,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetInstanceExpression(System.Linq.Expressions.ParameterExpression) -FNDA:92,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetInstanceExpression(System.Linq.Expressions.ParameterExpression) -DA:402,92 -DA:403,92 -DA:404,92 -FN:411,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceProviderExpression(System.Linq.Expressions.ParameterExpression) -FNDA:101,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceProviderExpression(System.Linq.Expressions.ParameterExpression) -DA:412,101 -DA:414,101 -DA:415,101 -FN:422,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceExpression(System.Linq.Expressions.ParameterExpression,System.Type) -FNDA:96,System.Linq.Expressions.Expression GraphQL.DI.DIObjectGraphType`2::GetServiceExpression(System.Linq.Expressions.ParameterExpression,System.Type) -DA:423,96 -DA:425,96 -DA:426,96 -DA:427,96 -DA:428,96 -DA:429,96 -DA:430,96 -BRDA:426,11,0,0 -BRDA:426,11,1,96 -FN:436,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateUnscopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) -FNDA:123,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateUnscopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) -DA:437,123 -DA:438,228 -DA:439,123 -DA:440,123 -DA:441,123 -BRDA:438,19,0,33 -BRDA:438,19,1,123 -FN:448,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateScopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) -FNDA:4,GraphQL.Resolvers.IFieldResolver GraphQL.DI.DIObjectGraphType`2::CreateScopedResolver(System.Linq.Expressions.Expression,System.Linq.Expressions.ParameterExpression) -DA:449,4 -DA:451,8 -DA:452,8 -DA:453,0 -DA:454,0 -DA:455,0 -DA:456,4 -DA:457,4 -DA:458,4 -BRDA:451,24,0,4 -BRDA:452,50,0,4 -BRDA:452,50,1,4 -BRDA:451,24,1,0 -BRDA:454,103,0,0 -BRDA:454,103,1,0 -FN:460,System.Type GraphQL.DI.DIObjectGraphType`2::GetTaskType(System.Type) -FNDA:4,System.Type GraphQL.DI.DIObjectGraphType`2::GetTaskType(System.Type) -DA:461,4 -DA:462,8 -DA:463,4 -DA:464,4 -DA:465,0 -DA:466,0 -DA:467,0 -DA:468,4 -BRDA:462,69,1,4 -BRDA:463,10,0,4 -BRDA:463,10,1,0 -BRDA:463,38,0,4 -BRDA:463,38,1,0 -BRDA:462,69,0,0 -FN:476,GraphQL.Types.QueryArgument GraphQL.DI.DIObjectGraphType`2::ProcessParameter(System.Reflection.MethodInfo,System.Reflection.ParameterInfo,System.Linq.Expressions.ParameterExpression,System.Boolean&,System.Linq.Expressions.Expression&) -FNDA:22,GraphQL.Types.QueryArgument GraphQL.DI.DIObjectGraphType`2::ProcessParameter(System.Reflection.MethodInfo,System.Reflection.ParameterInfo,System.Linq.Expressions.ParameterExpression,System.Boolean&,System.Linq.Expressions.Expression&) -DA:477,22 -DA:478,22 -DA:480,23 -DA:483,1 -DA:485,1 -DA:487,0 -DA:489,0 -DA:491,0 -DA:493,23 -DA:495,2 -DA:496,2 -DA:497,1 -DA:499,1 -DA:501,1 -DA:503,1 -DA:505,21 -DA:507,2 -DA:508,1 -DA:511,1 -DA:513,1 -DA:515,22 -DA:518,5 -DA:520,5 -DA:522,5 -DA:524,16 -DA:527,4 -DA:529,4 -DA:531,4 -DA:534,8 -DA:535,0 -DA:538,0 -DA:540,0 -DA:546,8 -DA:547,8 -DA:549,15 -DA:551,7 -DA:552,7 -DA:553,7 -DA:556,8 -DA:557,8 -DA:558,8 -DA:559,8 -DA:561,0 -DA:562,0 -DA:565,8 -DA:566,0 -DA:567,0 -DA:568,0 -DA:569,3 -DA:570,3 -DA:573,8 -DA:575,8 -DA:578,8 -DA:579,20 -BRDA:480,30,0,1 -BRDA:480,30,1,21 -BRDA:487,70,0,0 -BRDA:487,70,1,21 -BRDA:493,106,0,3 -BRDA:493,106,1,18 -BRDA:493,141,0,2 -BRDA:496,183,0,1 -BRDA:496,183,1,1 -BRDA:493,141,1,19 -BRDA:505,262,0,2 -BRDA:507,293,0,1 -BRDA:507,293,1,1 -BRDA:505,262,1,17 -BRDA:515,375,0,5 -BRDA:515,375,1,12 -BRDA:524,413,0,4 -BRDA:524,413,1,8 -BRDA:535,452,0,1 -BRDA:535,452,1,7 -BRDA:535,470,0,0 -BRDA:538,486,0,0 -BRDA:538,486,1,0 -BRDA:535,470,1,8 -BRDA:547,530,0,7 -BRDA:547,530,1,1 -BRDA:549,553,0,7 -BRDA:549,553,1,8 -BRDA:556,590,0,7 -BRDA:556,590,1,1 -BRDA:556,602,0,7 -BRDA:556,602,1,8 -BRDA:556,625,0,7 -BRDA:556,625,1,1 -BRDA:561,701,1,0 -BRDA:561,701,0,8 -BRDA:566,731,0,0 -BRDA:566,731,1,8 -BRDA:568,760,0,3 -BRDA:568,760,1,8 -FN:287,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|18_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass18_0&) -FNDA:256,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|18_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass18_0&) -DA:288,256 -DA:289,256 -DA:290,256 -DA:291,18 -DA:292,238 -DA:293,18 -DA:294,220 -DA:295,14 -DA:296,331 -DA:297,125 -DA:298,125 -DA:300,81 -DA:301,9 -DA:302,72 -DA:303,0 -DA:304,72 -DA:305,256 -BRDA:289,7,0,111 -BRDA:289,7,1,145 -BRDA:290,37,0,18 -BRDA:290,37,1,238 -BRDA:292,54,0,18 -BRDA:292,54,1,220 -BRDA:294,69,0,0 -BRDA:294,69,1,220 -BRDA:294,85,0,220 -BRDA:294,93,0,220 -BRDA:294,93,1,0 -BRDA:294,85,1,0 -BRDA:294,114,0,14 -BRDA:294,114,1,206 -BRDA:296,139,0,131 -BRDA:296,139,1,75 -BRDA:296,164,0,125 -BRDA:296,164,1,81 -BRDA:300,222,0,9 -BRDA:300,222,1,72 -BRDA:302,241,0,0 -BRDA:302,241,1,72 -FN:365,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|20_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass20_0&) -FNDA:12,GraphQL.DI.DIObjectGraphType`2/Nullability GraphQL.DI.DIObjectGraphType`2::g__Consider|20_3(System.Type,GraphQL.DI.DIObjectGraphType`2/<>c__DisplayClass20_0&) -DA:366,12 -DA:367,12 -DA:368,12 -DA:369,0 -DA:370,12 -DA:371,0 -DA:372,12 -DA:373,4 -DA:374,8 -DA:375,0 -DA:376,8 -DA:377,12 -BRDA:367,7,0,12 -BRDA:367,7,1,0 -BRDA:368,37,0,0 -BRDA:368,37,1,12 -BRDA:370,51,0,0 -BRDA:370,51,1,12 -BRDA:372,63,0,0 -BRDA:372,63,1,12 -BRDA:372,79,0,12 -BRDA:372,87,0,12 -BRDA:372,87,1,0 -BRDA:372,79,1,0 -BRDA:372,108,0,4 -BRDA:372,108,1,8 -BRDA:374,127,0,0 -BRDA:374,127,1,8 -FN:33,System.Void GraphQL.DI.DIObjectGraphType`2::.ctor() -FNDA:54,System.Void GraphQL.DI.DIObjectGraphType`2::.ctor() -DA:34,54 -DA:35,54 -DA:36,54 -DA:38,54 -DA:39,54 -DA:40,1 -DA:42,54 -DA:43,54 -DA:44,1 -DA:45,54 -DA:46,54 -DA:47,1 -DA:49,164 -DA:50,1 -DA:52,54 -DA:53,56 -DA:54,2 -DA:55,2 -DA:56,2 -DA:59,54 -DA:60,52 -DA:61,410 -DA:62,127 -DA:63,52 -DA:432,54 -DA:443,54 -DA:444,54 -BRDA:39,81,0,1 -BRDA:39,81,1,54 -BRDA:43,111,0,1 -BRDA:43,111,1,54 -BRDA:46,141,0,1 -BRDA:46,141,1,54 -BRDA:49,214,1,1 -BRDA:49,214,0,54 -BRDA:53,248,0,2 -BRDA:53,248,1,54 -BRDA:60,291,0,52 -BRDA:61,330,1,127 -BRDA:61,330,0,52 -BRDA:60,291,1,52 -FN:65,System.Void GraphQL.DI.DIObjectGraphType`2::.cctor() -FNDA:147,System.Void GraphQL.DI.DIObjectGraphType`2::.cctor() -DA:66,147 -DA:67,210 -DA:68,210 -DA:69,21 -DA:70,21 -DA:71,21 -BRDA:66,16,0,42 -BRDA:66,16,1,84 -BRDA:67,16,0,42 -BRDA:67,27,0,42 -BRDA:67,16,1,147 -BRDA:67,27,1,147 -BRDA:68,16,0,42 -BRDA:68,16,1,147 -LF:331 -LH:299 -BRF:246 -BRH:206 -FNF:20 -FNH:20 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\GraphTypeAttribute.cs -FN:22,System.Type GraphQL.DI.GraphTypeAttribute::get_Type() -FNDA:2,System.Type GraphQL.DI.GraphTypeAttribute::get_Type() -DA:23,2 -FN:14,System.Void GraphQL.DI.GraphTypeAttribute::.ctor(System.Type) -FNDA:2,System.Void GraphQL.DI.GraphTypeAttribute::.ctor(System.Type) -DA:15,2 -DA:16,2 -DA:17,2 -DA:18,2 -LF:5 -LH:5 -BRF:0 -BRH:0 -FNF:2 -FNH:2 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\MetadataAttribute.cs -FN:20,System.String GraphQL.DI.MetadataAttribute::get_Key() -FNDA:2,System.String GraphQL.DI.MetadataAttribute::get_Key() -DA:21,2 -FN:25,System.Object GraphQL.DI.MetadataAttribute::get_Value() -FNDA:2,System.Object GraphQL.DI.MetadataAttribute::get_Value() -DA:26,2 -FN:11,System.Void GraphQL.DI.MetadataAttribute::.ctor(System.String,System.Object) -FNDA:1,System.Void GraphQL.DI.MetadataAttribute::.ctor(System.String,System.Object) -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -LF:7 -LH:7 -BRF:0 -BRH:0 -FNF:3 -FNH:3 -end_of_record -SF:C:\Users\Shane\source\repos\GraphQL.DI\src\GraphQL.DI\NameAttribute.cs -FN:21,System.String GraphQL.DI.NameAttribute::get_Name() -FNDA:4,System.String GraphQL.DI.NameAttribute::get_Name() -DA:22,4 -FN:13,System.Void GraphQL.DI.NameAttribute::.ctor(System.String) -FNDA:3,System.Void GraphQL.DI.NameAttribute::.ctor(System.String) -DA:14,3 -DA:15,3 -DA:16,3 -DA:17,3 -LF:5 -LH:5 -BRF:0 -BRH:0 -FNF:2 -FNH:2 -end_of_record \ No newline at end of file From 72351c6b2d6d7acb400fa1704e29d2da1cfc8d73 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 16:23:55 -0400 Subject: [PATCH 15/31] test --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 155c916..8c738c7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] - run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:Include=[Shane32.GraphQL.DI]* -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== - name: Convert coverage report to clover & htmlsummary format if: ${{ matrix.os == 'ubuntu-latest' }} From 9d54aee4c5080405822c437f7105c2b67a5a9b1d Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 16:53:01 -0400 Subject: [PATCH 16/31] Try MS Test base --- src/Tests/DIObjectGraphTypeTests/Argument.cs | 21 +- src/Tests/DIObjectGraphTypeTests/Field.cs | 83 +++--- src/Tests/DIObjectGraphTypeTests/Graph.cs | 15 +- src/Tests/DIObjectGraphTypeTests/Nullable.cs | 279 ++++++++++--------- src/Tests/DIObjectGraphTypeTests/Services.cs | 11 +- src/Tests/Tests.csproj | 7 +- 6 files changed, 208 insertions(+), 208 deletions(-) diff --git a/src/Tests/DIObjectGraphTypeTests/Argument.cs b/src/Tests/DIObjectGraphTypeTests/Argument.cs index 9c13ce4..685a8fa 100644 --- a/src/Tests/DIObjectGraphTypeTests/Argument.cs +++ b/src/Tests/DIObjectGraphTypeTests/Argument.cs @@ -1,14 +1,15 @@ using System.ComponentModel; using GraphQL.DI; using GraphQL.Types; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Shouldly; -using Xunit; namespace DIObjectGraphTypeTests { + [TestClass] public class Argument : DIObjectGraphTypeTestBase { - [Fact] + [TestMethod] public void NonNullValue() { Configure(); @@ -22,7 +23,7 @@ public class CNonNullValue : DIObjectGraphBase public static int Field1(int arg) => arg; } - [Fact] + [TestMethod] public void NullableValue() { Configure(); @@ -36,7 +37,7 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1(int? arg) => arg; } - [Fact] + [TestMethod] public void NullableValueExplicit() { Configure(); @@ -50,7 +51,7 @@ public class CNullableValueExplicit : DIObjectGraphBase public static int? Field1([Optional] int arg) => arg; } - [Fact] + [TestMethod] public void NullableObject() { Configure(); @@ -64,7 +65,7 @@ public class CNullableObject : DIObjectGraphBase public static string Field1([Optional] string arg) => arg; } - [Fact] + [TestMethod] public void NonNullableObject() { Configure(); @@ -78,7 +79,7 @@ public class CNonNullableObject : DIObjectGraphBase public static string Field1([Required] string arg) => arg; } - [Fact] + [TestMethod] public void Name() { Configure(); @@ -92,7 +93,7 @@ public class CName : DIObjectGraphBase public static string Field1([Name("AltName")] string arg) => arg; } - [Fact] + [TestMethod] public void Description() { Configure(); @@ -104,10 +105,10 @@ public void Description() public class CDescription : DIObjectGraphBase { - public static string Field1([Description("TestDescription")] string arg) => arg; + public static string Field1([System.ComponentModel.Description("TestDescription")] string arg) => arg; } - [Fact] + [TestMethod] public void GraphType() { Configure(); diff --git a/src/Tests/DIObjectGraphTypeTests/Field.cs b/src/Tests/DIObjectGraphTypeTests/Field.cs index 089f5e8..c6c7540 100644 --- a/src/Tests/DIObjectGraphTypeTests/Field.cs +++ b/src/Tests/DIObjectGraphTypeTests/Field.cs @@ -8,13 +8,14 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using Shouldly; -using Xunit; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DIObjectGraphTypeTests { + [TestClass] public class Field : DIObjectGraphTypeTestBase { - [Fact] + [TestMethod] public void StaticMethod() { Configure(); @@ -29,7 +30,7 @@ public class CStaticMethod : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public void InstanceMethod() { Configure(true); @@ -42,7 +43,7 @@ public class CInstanceMethod : DIObjectGraphBase public string Field1() => "hello"; } - [Fact] + [TestMethod] public async Task StaticAsyncMethod() { Configure(); @@ -57,7 +58,7 @@ public class CStaticAsyncMethod : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public async Task InstanceAsyncMethod() { Configure(true); @@ -70,7 +71,7 @@ public class CInstanceAsyncMethod : DIObjectGraphBase public Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public void Name() { Configure(); @@ -84,7 +85,7 @@ public class CName : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public void Description() { Configure(); @@ -94,11 +95,11 @@ public void Description() public class CDescription : DIObjectGraphBase { - [Description("DescriptionTest")] + [System.ComponentModel.Description("DescriptionTest")] public static string Field1() => "hello"; } - [Fact] + [TestMethod] public void Obsolete() { Configure(); @@ -112,7 +113,7 @@ public class CObsolete : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public void Context() { Configure(); @@ -127,7 +128,7 @@ public class CContext : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => (string)context.Source; } - [Fact] + [TestMethod] public void Context_Typed() { Configure(); @@ -142,7 +143,7 @@ public class CContext_Typed : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => (string)context.Source; } - [Fact] + [TestMethod] public void Context_WrongType() { Should.Throw(() => Configure()); @@ -153,7 +154,7 @@ public class CContext_WrongType : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => context.Source; } - [Fact] + [TestMethod] public void Source() { Configure(); @@ -168,7 +169,7 @@ public class CSource : DIObjectGraphBase public static string Field1([FromSource] object source) => (string)source; } - [Fact] + [TestMethod] public void Source_WrongType() { Should.Throw(() => Configure()); @@ -179,7 +180,7 @@ public class CSource_WrongType : DIObjectGraphBase public static string Field1([FromSource] string source) => source; } - [Fact] + [TestMethod] public void ServiceProvider() { Configure(); @@ -193,7 +194,7 @@ public class CServiceProvider : DIObjectGraphBase public static string Field1(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService(); } - [Fact] + [TestMethod] public async Task ServiceProviderForScoped() { Configure(); @@ -208,7 +209,7 @@ public class CServiceProviderForScoped : DIObjectGraphBase public static Task Field1(IServiceProvider serviceProvider) => Task.FromResult(serviceProvider.GetRequiredService()); } - [Fact] + [TestMethod] public void NullableValue() { Configure(); @@ -221,7 +222,7 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1() => null; } - [Fact] + [TestMethod] public void NullableValueExplicit() { Configure(); @@ -235,7 +236,7 @@ public class CNullableValueExplicit : DIObjectGraphBase public static int Field1() => 1; } - [Fact] + [TestMethod] public void NonNullableValue() { Configure(); @@ -248,7 +249,7 @@ public class CNonNullableValue : DIObjectGraphBase public static int Field1() => 1; } - [Fact] + [TestMethod] public void Required() { Configure(); @@ -262,7 +263,7 @@ public class CRequired : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public async Task RequiredTask() { Configure(); @@ -276,7 +277,7 @@ public class CRequiredTask : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public void CustomType() { Configure(); @@ -290,7 +291,7 @@ public class CCustomType : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public async Task Concurrent() { Configure(); @@ -304,7 +305,7 @@ public class CConcurrent : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public void ConcurrentIgnoredForSynchronousMethods() { Configure(); @@ -318,7 +319,7 @@ public class CConcurrentIgnoredForSynchronousMethods : DIObjectGraphBase public static string Field1() => "hello"; } - [Fact] + [TestMethod] public async Task AlwaysConcurrentForStatic() { Configure(); @@ -331,7 +332,7 @@ public class CAlwaysConcurrentForStatic : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public async Task NotScopedWhenNoServices() { Configure(); @@ -345,7 +346,7 @@ public class CNotScopedWhenNoServices : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [Fact] + [TestMethod] public async Task AlwaysConcurrentForStaticUnlessService() { Configure(); @@ -359,7 +360,7 @@ public class CAlwaysConcurrentForStaticUnlessService : DIObjectGraphBase public static Task Field1([FromServices] string value) => Task.FromResult(value); } - [Fact] + [TestMethod] public async Task ScopedOnlyWhenSpecifiedWithServices() { Configure(); @@ -373,7 +374,7 @@ public class CScopedOnlyWhenSpecified : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [Fact] + [TestMethod] public async Task InheritsConcurrent() { Configure(); @@ -387,7 +388,7 @@ public class CInheritsConcurrent : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [Fact] + [TestMethod] public async Task InheritedConcurrentOverridable() { Configure(); @@ -402,17 +403,17 @@ public class CInheritedConcurrentOverridable : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [Theory] - [InlineData("Field1", typeof(GraphQLClrOutputTypeReference))] - [InlineData("Field2", typeof(NonNullGraphType>))] - [InlineData("Field3", typeof(NonNullGraphType>))] - [InlineData("Field4", typeof(GraphQLClrOutputTypeReference))] - [InlineData("Field5", typeof(GraphQLClrOutputTypeReference))] - //[InlineData("Field6", typeof(GraphQLClrOutputTypeReference)] //Need to fix graphql-dotnet bug 2441 first - [InlineData("Field7", typeof(GraphQLClrOutputTypeReference))] - [InlineData("Field8", typeof(NonNullGraphType>))] - [InlineData("Field9", typeof(GraphQLClrOutputTypeReference))] - [InlineData("Field10", typeof(GraphQLClrOutputTypeReference))] + [DataTestMethod] + [DataRow("Field1", typeof(GraphQLClrOutputTypeReference))] + [DataRow("Field2", typeof(NonNullGraphType>))] + [DataRow("Field3", typeof(NonNullGraphType>))] + [DataRow("Field4", typeof(GraphQLClrOutputTypeReference))] + [DataRow("Field5", typeof(GraphQLClrOutputTypeReference))] + //[DataRow("Field6", typeof(GraphQLClrOutputTypeReference)] //Need to fix graphql-dotnet bug 2441 first + [DataRow("Field7", typeof(GraphQLClrOutputTypeReference))] + [DataRow("Field8", typeof(NonNullGraphType>))] + [DataRow("Field9", typeof(GraphQLClrOutputTypeReference))] + [DataRow("Field10", typeof(GraphQLClrOutputTypeReference))] public void SupportsDataLoader(string fieldName, Type graphType) { Configure(true); diff --git a/src/Tests/DIObjectGraphTypeTests/Graph.cs b/src/Tests/DIObjectGraphTypeTests/Graph.cs index b8cc273..7d73fcb 100644 --- a/src/Tests/DIObjectGraphTypeTests/Graph.cs +++ b/src/Tests/DIObjectGraphTypeTests/Graph.cs @@ -4,13 +4,14 @@ using System.Reflection; using GraphQL.DI; using Shouldly; -using Xunit; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DIObjectGraphTypeTests { + [TestClass] public class Graph : DIObjectGraphTypeTestBase { - [Fact] + [TestMethod] public void GraphName() { Configure().Name.ShouldBe("TestGraphName"); @@ -19,16 +20,16 @@ public void GraphName() [Name("TestGraphName")] public class CGraphName : DIObjectGraphBase { } - [Fact] + [TestMethod] public void GraphDescription() { Configure().Description.ShouldBe("TestGraphDescription"); } - [Description("TestGraphDescription")] + [System.ComponentModel.Description("TestGraphDescription")] public class CGraphDescription : DIObjectGraphBase { } - [Fact] + [TestMethod] public void GraphObsolete() { Configure().DeprecationReason.ShouldBe("TestDeprecationReason"); @@ -37,7 +38,7 @@ public void GraphObsolete() [Obsolete("TestDeprecationReason")] public class CGraphObsolete : DIObjectGraphBase { } - [Fact] + [TestMethod] public void GraphMetadata() { Configure().GetMetadata("test").ShouldBe("value"); @@ -46,7 +47,7 @@ public void GraphMetadata() [Metadata("test", "value")] public class CGraphMetadata : DIObjectGraphBase { } - [Fact] + [TestMethod] public void CanOverrideMembers() { var test = new CCanOverrideMembersGraphType(); diff --git a/src/Tests/DIObjectGraphTypeTests/Nullable.cs b/src/Tests/DIObjectGraphTypeTests/Nullable.cs index ef4539d..5f332db 100644 --- a/src/Tests/DIObjectGraphTypeTests/Nullable.cs +++ b/src/Tests/DIObjectGraphTypeTests/Nullable.cs @@ -4,10 +4,11 @@ using GraphQL.DI; using Shouldly; using Tests.NullabilityTestClasses; -using Xunit; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DIObjectGraphTypeTests { + [TestClass] public class Nullable { //Verify... methods verify that .NET is building the classes @@ -15,20 +16,20 @@ public class Nullable // error, but simply indicates that the Method and Argument // tests may not be testing the anticipated scenarios //Method and Argument should always pass - [Theory] - [InlineData(typeof(NullableClass1), 1)] //default not nullable - [InlineData(typeof(NullableClass2), 2)] //default nullable - [InlineData(typeof(NullableClass5), null)] - [InlineData(typeof(NullableClass6), null)] - [InlineData(typeof(NullableClass7), 1)] //default not nullable - [InlineData(typeof(NullableClass8), 2)] //default nullable - [InlineData(typeof(NullableClass9), null)] - [InlineData(typeof(NullableClass10), null)] - [InlineData(typeof(NullableClass11), 1)] //default not nullable - [InlineData(typeof(NullableClass12), null)] - [InlineData(typeof(NullableClass13), 1)] //default not nullable - [InlineData(typeof(NullableClass14), 2)] //default nullable - [InlineData(typeof(NullableClass15), null)] + [DataTestMethod] + [DataRow(typeof(NullableClass1), 1)] //default not nullable + [DataRow(typeof(NullableClass2), 2)] //default nullable + [DataRow(typeof(NullableClass5), null)] + [DataRow(typeof(NullableClass6), null)] + [DataRow(typeof(NullableClass7), 1)] //default not nullable + [DataRow(typeof(NullableClass8), 2)] //default nullable + [DataRow(typeof(NullableClass9), null)] + [DataRow(typeof(NullableClass10), null)] + [DataRow(typeof(NullableClass11), 1)] //default not nullable + [DataRow(typeof(NullableClass12), null)] + [DataRow(typeof(NullableClass13), 1)] //default not nullable + [DataRow(typeof(NullableClass14), 2)] //default nullable + [DataRow(typeof(NullableClass15), null)] public void VerifyTestClass(Type type, int? nullableContext) { var actualHasNullableContext = type.CustomAttributes.FirstOrDefault( @@ -41,51 +42,51 @@ public void VerifyTestClass(Type type, int? nullableContext) } } - [Theory] - [InlineData(typeof(NullableClass1), "Field1", false, true)] - [InlineData(typeof(NullableClass1), "Field2", false, true)] - [InlineData(typeof(NullableClass1), "Field3", false, false)] - [InlineData(typeof(NullableClass1), "Field4", false, false)] - [InlineData(typeof(NullableClass1), "Field5", false, false)] - [InlineData(typeof(NullableClass1), "Field6", false, false)] - [InlineData(typeof(NullableClass1), "Field7", false, false)] - [InlineData(typeof(NullableClass1), "Field8", false, false)] - [InlineData(typeof(NullableClass2), "Field1", false, false)] - [InlineData(typeof(NullableClass2), "Field2", false, false)] - [InlineData(typeof(NullableClass2), "Field3", false, false)] - [InlineData(typeof(NullableClass2), "Field4", false, false)] - [InlineData(typeof(NullableClass2), "Field5", false, false)] - [InlineData(typeof(NullableClass2), "Field6", false, false)] - [InlineData(typeof(NullableClass2), "Field7", false, false)] - [InlineData(typeof(NullableClass2), "Field8", false, false)] - [InlineData(typeof(NullableClass2), "Field9", false, true)] - [InlineData(typeof(NullableClass2), "Field10", false, true)] - [InlineData(typeof(NullableClass5), "Test", false, true)] - [InlineData(typeof(NullableClass6), "Field1", false, true)] - [InlineData(typeof(NullableClass6), "Field2", false, true)] - [InlineData(typeof(NullableClass7), "Field1", false, false)] - [InlineData(typeof(NullableClass7), "Field2", false, false)] - [InlineData(typeof(NullableClass7), "Field3", false, true)] - [InlineData(typeof(NullableClass8), "Field1", false, false)] - [InlineData(typeof(NullableClass8), "Field2", false, false)] - [InlineData(typeof(NullableClass8), "Field3", false, true)] - [InlineData(typeof(NullableClass8), "Field4", false, false)] - [InlineData(typeof(NullableClass9), "Field1", true, true)] - [InlineData(typeof(NullableClass10), "Field1", true, true)] - [InlineData(typeof(NullableClass11), "Field1", false, false)] - [InlineData(typeof(NullableClass11), "Field2", true, false)] - [InlineData(typeof(NullableClass12), "Field1", false, true)] - [InlineData(typeof(NullableClass12), "Field2", true, false)] - [InlineData(typeof(NullableClass12), "Field3", true, false)] - [InlineData(typeof(NullableClass12), "Field4", false, true)] - [InlineData(typeof(NullableClass13), "Field1", false, false)] - [InlineData(typeof(NullableClass13), "Field2", false, false)] - [InlineData(typeof(NullableClass14), "Field1", false, false)] - [InlineData(typeof(NullableClass14), "Field2", false, false)] - [InlineData(typeof(NullableClass15), "Field1", false, true)] - [InlineData(typeof(NullableClass15), "Field2", true, false)] - [InlineData(typeof(NullableClass15), "Field3", true, false)] - [InlineData(typeof(NullableClass15), "Field4", false, true)] + [DataTestMethod] + [DataRow(typeof(NullableClass1), "Field1", false, true)] + [DataRow(typeof(NullableClass1), "Field2", false, true)] + [DataRow(typeof(NullableClass1), "Field3", false, false)] + [DataRow(typeof(NullableClass1), "Field4", false, false)] + [DataRow(typeof(NullableClass1), "Field5", false, false)] + [DataRow(typeof(NullableClass1), "Field6", false, false)] + [DataRow(typeof(NullableClass1), "Field7", false, false)] + [DataRow(typeof(NullableClass1), "Field8", false, false)] + [DataRow(typeof(NullableClass2), "Field1", false, false)] + [DataRow(typeof(NullableClass2), "Field2", false, false)] + [DataRow(typeof(NullableClass2), "Field3", false, false)] + [DataRow(typeof(NullableClass2), "Field4", false, false)] + [DataRow(typeof(NullableClass2), "Field5", false, false)] + [DataRow(typeof(NullableClass2), "Field6", false, false)] + [DataRow(typeof(NullableClass2), "Field7", false, false)] + [DataRow(typeof(NullableClass2), "Field8", false, false)] + [DataRow(typeof(NullableClass2), "Field9", false, true)] + [DataRow(typeof(NullableClass2), "Field10", false, true)] + [DataRow(typeof(NullableClass5), "Test", false, true)] + [DataRow(typeof(NullableClass6), "Field1", false, true)] + [DataRow(typeof(NullableClass6), "Field2", false, true)] + [DataRow(typeof(NullableClass7), "Field1", false, false)] + [DataRow(typeof(NullableClass7), "Field2", false, false)] + [DataRow(typeof(NullableClass7), "Field3", false, true)] + [DataRow(typeof(NullableClass8), "Field1", false, false)] + [DataRow(typeof(NullableClass8), "Field2", false, false)] + [DataRow(typeof(NullableClass8), "Field3", false, true)] + [DataRow(typeof(NullableClass8), "Field4", false, false)] + [DataRow(typeof(NullableClass9), "Field1", true, true)] + [DataRow(typeof(NullableClass10), "Field1", true, true)] + [DataRow(typeof(NullableClass11), "Field1", false, false)] + [DataRow(typeof(NullableClass11), "Field2", true, false)] + [DataRow(typeof(NullableClass12), "Field1", false, true)] + [DataRow(typeof(NullableClass12), "Field2", true, false)] + [DataRow(typeof(NullableClass12), "Field3", true, false)] + [DataRow(typeof(NullableClass12), "Field4", false, true)] + [DataRow(typeof(NullableClass13), "Field1", false, false)] + [DataRow(typeof(NullableClass13), "Field2", false, false)] + [DataRow(typeof(NullableClass14), "Field1", false, false)] + [DataRow(typeof(NullableClass14), "Field2", false, false)] + [DataRow(typeof(NullableClass15), "Field1", false, true)] + [DataRow(typeof(NullableClass15), "Field2", true, false)] + [DataRow(typeof(NullableClass15), "Field3", true, false)] + [DataRow(typeof(NullableClass15), "Field4", false, true)] public void VerifyTestMethod(Type type, string methodName, bool hasNullable, bool hasNullableContext) { var method = type.GetMethod(methodName); @@ -100,23 +101,23 @@ public void VerifyTestMethod(Type type, string methodName, bool hasNullable, boo actualHasNullableContext.ShouldBe(hasNullableContext); } - [Theory] - [InlineData(typeof(NullableClass9), "Field1", "arg1", false)] - [InlineData(typeof(NullableClass9), "Field1", "arg2", false)] - [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] - [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] - [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] - [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] - [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg4", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg5", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg1", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg2", true)] - [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg4", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] + [DataTestMethod] + [DataRow(typeof(NullableClass9), "Field1", "arg1", false)] + [DataRow(typeof(NullableClass9), "Field1", "arg2", false)] + [DataRow(typeof(NullableClass10), "Field1", "arg1", false)] + [DataRow(typeof(NullableClass10), "Field1", "arg2", false)] + [DataRow(typeof(NullableClass11), "Field2", "arg1", false)] + [DataRow(typeof(NullableClass11), "Field2", "arg2", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg1", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg2", true)] + [DataRow(typeof(NullableClass13), "Field2", "arg3", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg4", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg5", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg1", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg2", true)] + [DataRow(typeof(NullableClass14), "Field2", "arg3", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg4", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg5", false)] public void VerifyTestArgument(Type type, string methodName, string argumentName, bool hasNullable) { var method = type.GetMethod(methodName); @@ -126,51 +127,51 @@ public void VerifyTestArgument(Type type, string methodName, string argumentName actualHasNullable.ShouldBe(hasNullable); } - [Theory] - [InlineData(typeof(NullableClass1), "Field1", true)] - [InlineData(typeof(NullableClass1), "Field2", false)] - [InlineData(typeof(NullableClass1), "Field3", false)] - [InlineData(typeof(NullableClass1), "Field4", true)] - [InlineData(typeof(NullableClass1), "Field5", true)] - [InlineData(typeof(NullableClass1), "Field6", false)] - [InlineData(typeof(NullableClass1), "Field7", false)] - [InlineData(typeof(NullableClass1), "Field8", true)] - [InlineData(typeof(NullableClass2), "Field1", true)] - [InlineData(typeof(NullableClass2), "Field2", false)] - [InlineData(typeof(NullableClass2), "Field3", false)] - [InlineData(typeof(NullableClass2), "Field4", true)] - [InlineData(typeof(NullableClass2), "Field5", true)] - [InlineData(typeof(NullableClass2), "Field6", false)] - [InlineData(typeof(NullableClass2), "Field7", true)] - [InlineData(typeof(NullableClass2), "Field8", true)] - [InlineData(typeof(NullableClass2), "Field9", false)] - [InlineData(typeof(NullableClass2), "Field10", true)] - [InlineData(typeof(NullableClass5), "Test", false)] - [InlineData(typeof(NullableClass6), "Field1", false)] - [InlineData(typeof(NullableClass6), "Field2", true)] - [InlineData(typeof(NullableClass7), "Field1", false)] - [InlineData(typeof(NullableClass7), "Field2", false)] - [InlineData(typeof(NullableClass7), "Field3", true)] - [InlineData(typeof(NullableClass8), "Field1", true)] - [InlineData(typeof(NullableClass8), "Field2", true)] - [InlineData(typeof(NullableClass8), "Field3", false)] - [InlineData(typeof(NullableClass8), "Field4", false)] - [InlineData(typeof(NullableClass9), "Field1", false)] - [InlineData(typeof(NullableClass10), "Field1", true)] - [InlineData(typeof(NullableClass11), "Field1", false)] - [InlineData(typeof(NullableClass11), "Field2", true)] - [InlineData(typeof(NullableClass12), "Field1", false)] - [InlineData(typeof(NullableClass12), "Field2", true)] - [InlineData(typeof(NullableClass12), "Field3", true)] - [InlineData(typeof(NullableClass12), "Field4", true)] - [InlineData(typeof(NullableClass13), "Field1", false)] - [InlineData(typeof(NullableClass13), "Field2", false)] - [InlineData(typeof(NullableClass14), "Field1", true)] - [InlineData(typeof(NullableClass14), "Field2", true)] - [InlineData(typeof(NullableClass15), "Field1", false)] - [InlineData(typeof(NullableClass15), "Field2", true)] - [InlineData(typeof(NullableClass15), "Field3", true)] - [InlineData(typeof(NullableClass15), "Field4", true)] + [DataTestMethod] + [DataRow(typeof(NullableClass1), "Field1", true)] + [DataRow(typeof(NullableClass1), "Field2", false)] + [DataRow(typeof(NullableClass1), "Field3", false)] + [DataRow(typeof(NullableClass1), "Field4", true)] + [DataRow(typeof(NullableClass1), "Field5", true)] + [DataRow(typeof(NullableClass1), "Field6", false)] + [DataRow(typeof(NullableClass1), "Field7", false)] + [DataRow(typeof(NullableClass1), "Field8", true)] + [DataRow(typeof(NullableClass2), "Field1", true)] + [DataRow(typeof(NullableClass2), "Field2", false)] + [DataRow(typeof(NullableClass2), "Field3", false)] + [DataRow(typeof(NullableClass2), "Field4", true)] + [DataRow(typeof(NullableClass2), "Field5", true)] + [DataRow(typeof(NullableClass2), "Field6", false)] + [DataRow(typeof(NullableClass2), "Field7", true)] + [DataRow(typeof(NullableClass2), "Field8", true)] + [DataRow(typeof(NullableClass2), "Field9", false)] + [DataRow(typeof(NullableClass2), "Field10", true)] + [DataRow(typeof(NullableClass5), "Test", false)] + [DataRow(typeof(NullableClass6), "Field1", false)] + [DataRow(typeof(NullableClass6), "Field2", true)] + [DataRow(typeof(NullableClass7), "Field1", false)] + [DataRow(typeof(NullableClass7), "Field2", false)] + [DataRow(typeof(NullableClass7), "Field3", true)] + [DataRow(typeof(NullableClass8), "Field1", true)] + [DataRow(typeof(NullableClass8), "Field2", true)] + [DataRow(typeof(NullableClass8), "Field3", false)] + [DataRow(typeof(NullableClass8), "Field4", false)] + [DataRow(typeof(NullableClass9), "Field1", false)] + [DataRow(typeof(NullableClass10), "Field1", true)] + [DataRow(typeof(NullableClass11), "Field1", false)] + [DataRow(typeof(NullableClass11), "Field2", true)] + [DataRow(typeof(NullableClass12), "Field1", false)] + [DataRow(typeof(NullableClass12), "Field2", true)] + [DataRow(typeof(NullableClass12), "Field3", true)] + [DataRow(typeof(NullableClass12), "Field4", true)] + [DataRow(typeof(NullableClass13), "Field1", false)] + [DataRow(typeof(NullableClass13), "Field2", false)] + [DataRow(typeof(NullableClass14), "Field1", true)] + [DataRow(typeof(NullableClass14), "Field2", true)] + [DataRow(typeof(NullableClass15), "Field1", false)] + [DataRow(typeof(NullableClass15), "Field2", true)] + [DataRow(typeof(NullableClass15), "Field3", true)] + [DataRow(typeof(NullableClass15), "Field4", true)] public void Method(Type type, string methodName, bool expected) { var method = type.GetMethod(methodName); @@ -178,23 +179,23 @@ public void Method(Type type, string methodName, bool expected) nullable.ShouldBe(expected); } - [Theory] - [InlineData(typeof(NullableClass9), "Field1", "arg1", true)] - [InlineData(typeof(NullableClass9), "Field1", "arg2", true)] - [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] - [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] - [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] - [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] - [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] - [InlineData(typeof(NullableClass13), "Field2", "arg4", true)] - [InlineData(typeof(NullableClass13), "Field2", "arg5", true)] - [InlineData(typeof(NullableClass14), "Field2", "arg1", true)] - [InlineData(typeof(NullableClass14), "Field2", "arg2", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] - [InlineData(typeof(NullableClass14), "Field2", "arg4", true)] - [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] + [DataTestMethod] + [DataRow(typeof(NullableClass9), "Field1", "arg1", true)] + [DataRow(typeof(NullableClass9), "Field1", "arg2", true)] + [DataRow(typeof(NullableClass10), "Field1", "arg1", false)] + [DataRow(typeof(NullableClass10), "Field1", "arg2", false)] + [DataRow(typeof(NullableClass11), "Field2", "arg1", false)] + [DataRow(typeof(NullableClass11), "Field2", "arg2", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg1", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg2", true)] + [DataRow(typeof(NullableClass13), "Field2", "arg3", false)] + [DataRow(typeof(NullableClass13), "Field2", "arg4", true)] + [DataRow(typeof(NullableClass13), "Field2", "arg5", true)] + [DataRow(typeof(NullableClass14), "Field2", "arg1", true)] + [DataRow(typeof(NullableClass14), "Field2", "arg2", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg3", false)] + [DataRow(typeof(NullableClass14), "Field2", "arg4", true)] + [DataRow(typeof(NullableClass14), "Field2", "arg5", false)] public void Argument(Type type, string methodName, string argumentName, bool expected) { var method = type.GetMethod(methodName); diff --git a/src/Tests/DIObjectGraphTypeTests/Services.cs b/src/Tests/DIObjectGraphTypeTests/Services.cs index c367217..cef2120 100644 --- a/src/Tests/DIObjectGraphTypeTests/Services.cs +++ b/src/Tests/DIObjectGraphTypeTests/Services.cs @@ -1,16 +1,15 @@ using System; -using System.ComponentModel; using System.Threading.Tasks; using GraphQL.DI; -using GraphQL.Types; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Shouldly; -using Xunit; namespace DIObjectGraphTypeTests { + [TestClass] public class Services : DIObjectGraphTypeTestBase { - [Fact] + [TestMethod] public void Service() { Configure(); @@ -24,7 +23,7 @@ public class CService : DIObjectGraphBase public static string Field1([FromServices] string arg) => arg; } - [Fact] + [TestMethod] public void ServiceMissingThrows() { Configure(); @@ -33,7 +32,7 @@ public void ServiceMissingThrows() Verify(false); } - [Fact] + [TestMethod] public async Task ScopedService() { Configure(); diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 118d0fb..23f44a9 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -16,11 +16,8 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 5756afc1b00e358602f02655f617b6392cfc8096 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 16:54:55 -0400 Subject: [PATCH 17/31] Try yml again --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c738c7..461a5cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] - run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + run: dotnet test --no-restore -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== - name: Convert coverage report to clover & htmlsummary format if: ${{ matrix.os == 'ubuntu-latest' }} From a0969935a0f3045b864a0dc49b8d206c367a0bf2 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:04:15 -0400 Subject: [PATCH 18/31] try again --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 461a5cf..29d41a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: - name: Build solution [Release] run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 - name: Build solution [Debug] - run: dotnet build --no-restore -p:NoWarn=CS1591 + run: dotnet build --no-restore -p:NoWarn=CS1591 -p:DebugType=pdbonly - name: Test solution [Debug] run: dotnet test --no-restore -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== From 8fda7b4e3e8ed41a9d3366eccb80eab4e7ff37cb Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:08:19 -0400 Subject: [PATCH 19/31] test --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 29d41a8..b332d62 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,12 +34,12 @@ jobs: NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Install dependencies run: dotnet restore - - name: Build solution [Release] - run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 + #- name: Build solution [Release] + # run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 -p:DebugType=pdbonly - name: Test solution [Debug] - run: dotnet test --no-restore -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info + run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== - name: Convert coverage report to clover & htmlsummary format if: ${{ matrix.os == 'ubuntu-latest' }} From 49c64e128a77a2b070e1235adfd4a1c506fe633f Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:12:24 -0400 Subject: [PATCH 20/31] test --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b332d62..06cf382 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: - - ubuntu-latest + #- ubuntu-latest - windows-latest steps: - name: Checkout source From 31ed141daeba4d14d77af6a09baeb82e5961640c Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:16:47 -0400 Subject: [PATCH 21/31] update --- .github/workflows/test.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 06cf382..131e2d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: - #- ubuntu-latest + - ubuntu-latest - windows-latest steps: - name: Checkout source @@ -29,13 +29,17 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: '3.1.x' + - name: Use .NET Core 5.0 SDK + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '5.0.x' source-url: https://nuget.pkg.github.com/Shane32/index.json env: NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Install dependencies run: dotnet restore - #- name: Build solution [Release] - # run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 + - name: Build solution [Release] + run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 - name: Build solution [Debug] run: dotnet build --no-restore -p:NoWarn=CS1591 -p:DebugType=pdbonly - name: Test solution [Debug] From 07e4ca60e2f515fcf6cfe214f7bccfc102d34c80 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:49:51 -0400 Subject: [PATCH 22/31] fix --- .github/workflows/test.yml | 2 +- Directory.Build.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 131e2d7..1aa58b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: - name: Build solution [Release] run: dotnet build --no-restore -c Release -p:NoWarn=CS1591 - name: Build solution [Debug] - run: dotnet build --no-restore -p:NoWarn=CS1591 -p:DebugType=pdbonly + run: dotnet build --no-restore -p:NoWarn=CS1591 - name: Test solution [Debug] run: dotnet test --no-restore --no-build -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../../${{ matrix.os }}.lcov.info # ==== code coverage reports (ubuntu-latest only) ==== diff --git a/Directory.Build.props b/Directory.Build.props index e718507..a7a3d2c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ true - True + True embedded true From 3b33f2e49b358365cb7753b9c45d6225ee069e1b Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:49:59 -0400 Subject: [PATCH 23/31] Revert "Try MS Test base" This reverts commit 9d54aee4c5080405822c437f7105c2b67a5a9b1d. --- src/Tests/DIObjectGraphTypeTests/Argument.cs | 21 +- src/Tests/DIObjectGraphTypeTests/Field.cs | 83 +++--- src/Tests/DIObjectGraphTypeTests/Graph.cs | 15 +- src/Tests/DIObjectGraphTypeTests/Nullable.cs | 279 +++++++++---------- src/Tests/DIObjectGraphTypeTests/Services.cs | 11 +- src/Tests/Tests.csproj | 7 +- 6 files changed, 208 insertions(+), 208 deletions(-) diff --git a/src/Tests/DIObjectGraphTypeTests/Argument.cs b/src/Tests/DIObjectGraphTypeTests/Argument.cs index 685a8fa..9c13ce4 100644 --- a/src/Tests/DIObjectGraphTypeTests/Argument.cs +++ b/src/Tests/DIObjectGraphTypeTests/Argument.cs @@ -1,15 +1,14 @@ using System.ComponentModel; using GraphQL.DI; using GraphQL.Types; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Shouldly; +using Xunit; namespace DIObjectGraphTypeTests { - [TestClass] public class Argument : DIObjectGraphTypeTestBase { - [TestMethod] + [Fact] public void NonNullValue() { Configure(); @@ -23,7 +22,7 @@ public class CNonNullValue : DIObjectGraphBase public static int Field1(int arg) => arg; } - [TestMethod] + [Fact] public void NullableValue() { Configure(); @@ -37,7 +36,7 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1(int? arg) => arg; } - [TestMethod] + [Fact] public void NullableValueExplicit() { Configure(); @@ -51,7 +50,7 @@ public class CNullableValueExplicit : DIObjectGraphBase public static int? Field1([Optional] int arg) => arg; } - [TestMethod] + [Fact] public void NullableObject() { Configure(); @@ -65,7 +64,7 @@ public class CNullableObject : DIObjectGraphBase public static string Field1([Optional] string arg) => arg; } - [TestMethod] + [Fact] public void NonNullableObject() { Configure(); @@ -79,7 +78,7 @@ public class CNonNullableObject : DIObjectGraphBase public static string Field1([Required] string arg) => arg; } - [TestMethod] + [Fact] public void Name() { Configure(); @@ -93,7 +92,7 @@ public class CName : DIObjectGraphBase public static string Field1([Name("AltName")] string arg) => arg; } - [TestMethod] + [Fact] public void Description() { Configure(); @@ -105,10 +104,10 @@ public void Description() public class CDescription : DIObjectGraphBase { - public static string Field1([System.ComponentModel.Description("TestDescription")] string arg) => arg; + public static string Field1([Description("TestDescription")] string arg) => arg; } - [TestMethod] + [Fact] public void GraphType() { Configure(); diff --git a/src/Tests/DIObjectGraphTypeTests/Field.cs b/src/Tests/DIObjectGraphTypeTests/Field.cs index c6c7540..089f5e8 100644 --- a/src/Tests/DIObjectGraphTypeTests/Field.cs +++ b/src/Tests/DIObjectGraphTypeTests/Field.cs @@ -8,14 +8,13 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using Shouldly; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; namespace DIObjectGraphTypeTests { - [TestClass] public class Field : DIObjectGraphTypeTestBase { - [TestMethod] + [Fact] public void StaticMethod() { Configure(); @@ -30,7 +29,7 @@ public class CStaticMethod : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public void InstanceMethod() { Configure(true); @@ -43,7 +42,7 @@ public class CInstanceMethod : DIObjectGraphBase public string Field1() => "hello"; } - [TestMethod] + [Fact] public async Task StaticAsyncMethod() { Configure(); @@ -58,7 +57,7 @@ public class CStaticAsyncMethod : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public async Task InstanceAsyncMethod() { Configure(true); @@ -71,7 +70,7 @@ public class CInstanceAsyncMethod : DIObjectGraphBase public Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public void Name() { Configure(); @@ -85,7 +84,7 @@ public class CName : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public void Description() { Configure(); @@ -95,11 +94,11 @@ public void Description() public class CDescription : DIObjectGraphBase { - [System.ComponentModel.Description("DescriptionTest")] + [Description("DescriptionTest")] public static string Field1() => "hello"; } - [TestMethod] + [Fact] public void Obsolete() { Configure(); @@ -113,7 +112,7 @@ public class CObsolete : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public void Context() { Configure(); @@ -128,7 +127,7 @@ public class CContext : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => (string)context.Source; } - [TestMethod] + [Fact] public void Context_Typed() { Configure(); @@ -143,7 +142,7 @@ public class CContext_Typed : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => (string)context.Source; } - [TestMethod] + [Fact] public void Context_WrongType() { Should.Throw(() => Configure()); @@ -154,7 +153,7 @@ public class CContext_WrongType : DIObjectGraphBase public static string Field1(IResolveFieldContext context) => context.Source; } - [TestMethod] + [Fact] public void Source() { Configure(); @@ -169,7 +168,7 @@ public class CSource : DIObjectGraphBase public static string Field1([FromSource] object source) => (string)source; } - [TestMethod] + [Fact] public void Source_WrongType() { Should.Throw(() => Configure()); @@ -180,7 +179,7 @@ public class CSource_WrongType : DIObjectGraphBase public static string Field1([FromSource] string source) => source; } - [TestMethod] + [Fact] public void ServiceProvider() { Configure(); @@ -194,7 +193,7 @@ public class CServiceProvider : DIObjectGraphBase public static string Field1(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService(); } - [TestMethod] + [Fact] public async Task ServiceProviderForScoped() { Configure(); @@ -209,7 +208,7 @@ public class CServiceProviderForScoped : DIObjectGraphBase public static Task Field1(IServiceProvider serviceProvider) => Task.FromResult(serviceProvider.GetRequiredService()); } - [TestMethod] + [Fact] public void NullableValue() { Configure(); @@ -222,7 +221,7 @@ public class CNullableValue : DIObjectGraphBase public static int? Field1() => null; } - [TestMethod] + [Fact] public void NullableValueExplicit() { Configure(); @@ -236,7 +235,7 @@ public class CNullableValueExplicit : DIObjectGraphBase public static int Field1() => 1; } - [TestMethod] + [Fact] public void NonNullableValue() { Configure(); @@ -249,7 +248,7 @@ public class CNonNullableValue : DIObjectGraphBase public static int Field1() => 1; } - [TestMethod] + [Fact] public void Required() { Configure(); @@ -263,7 +262,7 @@ public class CRequired : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public async Task RequiredTask() { Configure(); @@ -277,7 +276,7 @@ public class CRequiredTask : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public void CustomType() { Configure(); @@ -291,7 +290,7 @@ public class CCustomType : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public async Task Concurrent() { Configure(); @@ -305,7 +304,7 @@ public class CConcurrent : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public void ConcurrentIgnoredForSynchronousMethods() { Configure(); @@ -319,7 +318,7 @@ public class CConcurrentIgnoredForSynchronousMethods : DIObjectGraphBase public static string Field1() => "hello"; } - [TestMethod] + [Fact] public async Task AlwaysConcurrentForStatic() { Configure(); @@ -332,7 +331,7 @@ public class CAlwaysConcurrentForStatic : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public async Task NotScopedWhenNoServices() { Configure(); @@ -346,7 +345,7 @@ public class CNotScopedWhenNoServices : DIObjectGraphBase public static Task Field1() => Task.FromResult("hello"); } - [TestMethod] + [Fact] public async Task AlwaysConcurrentForStaticUnlessService() { Configure(); @@ -360,7 +359,7 @@ public class CAlwaysConcurrentForStaticUnlessService : DIObjectGraphBase public static Task Field1([FromServices] string value) => Task.FromResult(value); } - [TestMethod] + [Fact] public async Task ScopedOnlyWhenSpecifiedWithServices() { Configure(); @@ -374,7 +373,7 @@ public class CScopedOnlyWhenSpecified : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [TestMethod] + [Fact] public async Task InheritsConcurrent() { Configure(); @@ -388,7 +387,7 @@ public class CInheritsConcurrent : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [TestMethod] + [Fact] public async Task InheritedConcurrentOverridable() { Configure(); @@ -403,17 +402,17 @@ public class CInheritedConcurrentOverridable : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } - [DataTestMethod] - [DataRow("Field1", typeof(GraphQLClrOutputTypeReference))] - [DataRow("Field2", typeof(NonNullGraphType>))] - [DataRow("Field3", typeof(NonNullGraphType>))] - [DataRow("Field4", typeof(GraphQLClrOutputTypeReference))] - [DataRow("Field5", typeof(GraphQLClrOutputTypeReference))] - //[DataRow("Field6", typeof(GraphQLClrOutputTypeReference)] //Need to fix graphql-dotnet bug 2441 first - [DataRow("Field7", typeof(GraphQLClrOutputTypeReference))] - [DataRow("Field8", typeof(NonNullGraphType>))] - [DataRow("Field9", typeof(GraphQLClrOutputTypeReference))] - [DataRow("Field10", typeof(GraphQLClrOutputTypeReference))] + [Theory] + [InlineData("Field1", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field2", typeof(NonNullGraphType>))] + [InlineData("Field3", typeof(NonNullGraphType>))] + [InlineData("Field4", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field5", typeof(GraphQLClrOutputTypeReference))] + //[InlineData("Field6", typeof(GraphQLClrOutputTypeReference)] //Need to fix graphql-dotnet bug 2441 first + [InlineData("Field7", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field8", typeof(NonNullGraphType>))] + [InlineData("Field9", typeof(GraphQLClrOutputTypeReference))] + [InlineData("Field10", typeof(GraphQLClrOutputTypeReference))] public void SupportsDataLoader(string fieldName, Type graphType) { Configure(true); diff --git a/src/Tests/DIObjectGraphTypeTests/Graph.cs b/src/Tests/DIObjectGraphTypeTests/Graph.cs index 7d73fcb..b8cc273 100644 --- a/src/Tests/DIObjectGraphTypeTests/Graph.cs +++ b/src/Tests/DIObjectGraphTypeTests/Graph.cs @@ -4,14 +4,13 @@ using System.Reflection; using GraphQL.DI; using Shouldly; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; namespace DIObjectGraphTypeTests { - [TestClass] public class Graph : DIObjectGraphTypeTestBase { - [TestMethod] + [Fact] public void GraphName() { Configure().Name.ShouldBe("TestGraphName"); @@ -20,16 +19,16 @@ public void GraphName() [Name("TestGraphName")] public class CGraphName : DIObjectGraphBase { } - [TestMethod] + [Fact] public void GraphDescription() { Configure().Description.ShouldBe("TestGraphDescription"); } - [System.ComponentModel.Description("TestGraphDescription")] + [Description("TestGraphDescription")] public class CGraphDescription : DIObjectGraphBase { } - [TestMethod] + [Fact] public void GraphObsolete() { Configure().DeprecationReason.ShouldBe("TestDeprecationReason"); @@ -38,7 +37,7 @@ public void GraphObsolete() [Obsolete("TestDeprecationReason")] public class CGraphObsolete : DIObjectGraphBase { } - [TestMethod] + [Fact] public void GraphMetadata() { Configure().GetMetadata("test").ShouldBe("value"); @@ -47,7 +46,7 @@ public void GraphMetadata() [Metadata("test", "value")] public class CGraphMetadata : DIObjectGraphBase { } - [TestMethod] + [Fact] public void CanOverrideMembers() { var test = new CCanOverrideMembersGraphType(); diff --git a/src/Tests/DIObjectGraphTypeTests/Nullable.cs b/src/Tests/DIObjectGraphTypeTests/Nullable.cs index 5f332db..ef4539d 100644 --- a/src/Tests/DIObjectGraphTypeTests/Nullable.cs +++ b/src/Tests/DIObjectGraphTypeTests/Nullable.cs @@ -4,11 +4,10 @@ using GraphQL.DI; using Shouldly; using Tests.NullabilityTestClasses; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; namespace DIObjectGraphTypeTests { - [TestClass] public class Nullable { //Verify... methods verify that .NET is building the classes @@ -16,20 +15,20 @@ public class Nullable // error, but simply indicates that the Method and Argument // tests may not be testing the anticipated scenarios //Method and Argument should always pass - [DataTestMethod] - [DataRow(typeof(NullableClass1), 1)] //default not nullable - [DataRow(typeof(NullableClass2), 2)] //default nullable - [DataRow(typeof(NullableClass5), null)] - [DataRow(typeof(NullableClass6), null)] - [DataRow(typeof(NullableClass7), 1)] //default not nullable - [DataRow(typeof(NullableClass8), 2)] //default nullable - [DataRow(typeof(NullableClass9), null)] - [DataRow(typeof(NullableClass10), null)] - [DataRow(typeof(NullableClass11), 1)] //default not nullable - [DataRow(typeof(NullableClass12), null)] - [DataRow(typeof(NullableClass13), 1)] //default not nullable - [DataRow(typeof(NullableClass14), 2)] //default nullable - [DataRow(typeof(NullableClass15), null)] + [Theory] + [InlineData(typeof(NullableClass1), 1)] //default not nullable + [InlineData(typeof(NullableClass2), 2)] //default nullable + [InlineData(typeof(NullableClass5), null)] + [InlineData(typeof(NullableClass6), null)] + [InlineData(typeof(NullableClass7), 1)] //default not nullable + [InlineData(typeof(NullableClass8), 2)] //default nullable + [InlineData(typeof(NullableClass9), null)] + [InlineData(typeof(NullableClass10), null)] + [InlineData(typeof(NullableClass11), 1)] //default not nullable + [InlineData(typeof(NullableClass12), null)] + [InlineData(typeof(NullableClass13), 1)] //default not nullable + [InlineData(typeof(NullableClass14), 2)] //default nullable + [InlineData(typeof(NullableClass15), null)] public void VerifyTestClass(Type type, int? nullableContext) { var actualHasNullableContext = type.CustomAttributes.FirstOrDefault( @@ -42,51 +41,51 @@ public void VerifyTestClass(Type type, int? nullableContext) } } - [DataTestMethod] - [DataRow(typeof(NullableClass1), "Field1", false, true)] - [DataRow(typeof(NullableClass1), "Field2", false, true)] - [DataRow(typeof(NullableClass1), "Field3", false, false)] - [DataRow(typeof(NullableClass1), "Field4", false, false)] - [DataRow(typeof(NullableClass1), "Field5", false, false)] - [DataRow(typeof(NullableClass1), "Field6", false, false)] - [DataRow(typeof(NullableClass1), "Field7", false, false)] - [DataRow(typeof(NullableClass1), "Field8", false, false)] - [DataRow(typeof(NullableClass2), "Field1", false, false)] - [DataRow(typeof(NullableClass2), "Field2", false, false)] - [DataRow(typeof(NullableClass2), "Field3", false, false)] - [DataRow(typeof(NullableClass2), "Field4", false, false)] - [DataRow(typeof(NullableClass2), "Field5", false, false)] - [DataRow(typeof(NullableClass2), "Field6", false, false)] - [DataRow(typeof(NullableClass2), "Field7", false, false)] - [DataRow(typeof(NullableClass2), "Field8", false, false)] - [DataRow(typeof(NullableClass2), "Field9", false, true)] - [DataRow(typeof(NullableClass2), "Field10", false, true)] - [DataRow(typeof(NullableClass5), "Test", false, true)] - [DataRow(typeof(NullableClass6), "Field1", false, true)] - [DataRow(typeof(NullableClass6), "Field2", false, true)] - [DataRow(typeof(NullableClass7), "Field1", false, false)] - [DataRow(typeof(NullableClass7), "Field2", false, false)] - [DataRow(typeof(NullableClass7), "Field3", false, true)] - [DataRow(typeof(NullableClass8), "Field1", false, false)] - [DataRow(typeof(NullableClass8), "Field2", false, false)] - [DataRow(typeof(NullableClass8), "Field3", false, true)] - [DataRow(typeof(NullableClass8), "Field4", false, false)] - [DataRow(typeof(NullableClass9), "Field1", true, true)] - [DataRow(typeof(NullableClass10), "Field1", true, true)] - [DataRow(typeof(NullableClass11), "Field1", false, false)] - [DataRow(typeof(NullableClass11), "Field2", true, false)] - [DataRow(typeof(NullableClass12), "Field1", false, true)] - [DataRow(typeof(NullableClass12), "Field2", true, false)] - [DataRow(typeof(NullableClass12), "Field3", true, false)] - [DataRow(typeof(NullableClass12), "Field4", false, true)] - [DataRow(typeof(NullableClass13), "Field1", false, false)] - [DataRow(typeof(NullableClass13), "Field2", false, false)] - [DataRow(typeof(NullableClass14), "Field1", false, false)] - [DataRow(typeof(NullableClass14), "Field2", false, false)] - [DataRow(typeof(NullableClass15), "Field1", false, true)] - [DataRow(typeof(NullableClass15), "Field2", true, false)] - [DataRow(typeof(NullableClass15), "Field3", true, false)] - [DataRow(typeof(NullableClass15), "Field4", false, true)] + [Theory] + [InlineData(typeof(NullableClass1), "Field1", false, true)] + [InlineData(typeof(NullableClass1), "Field2", false, true)] + [InlineData(typeof(NullableClass1), "Field3", false, false)] + [InlineData(typeof(NullableClass1), "Field4", false, false)] + [InlineData(typeof(NullableClass1), "Field5", false, false)] + [InlineData(typeof(NullableClass1), "Field6", false, false)] + [InlineData(typeof(NullableClass1), "Field7", false, false)] + [InlineData(typeof(NullableClass1), "Field8", false, false)] + [InlineData(typeof(NullableClass2), "Field1", false, false)] + [InlineData(typeof(NullableClass2), "Field2", false, false)] + [InlineData(typeof(NullableClass2), "Field3", false, false)] + [InlineData(typeof(NullableClass2), "Field4", false, false)] + [InlineData(typeof(NullableClass2), "Field5", false, false)] + [InlineData(typeof(NullableClass2), "Field6", false, false)] + [InlineData(typeof(NullableClass2), "Field7", false, false)] + [InlineData(typeof(NullableClass2), "Field8", false, false)] + [InlineData(typeof(NullableClass2), "Field9", false, true)] + [InlineData(typeof(NullableClass2), "Field10", false, true)] + [InlineData(typeof(NullableClass5), "Test", false, true)] + [InlineData(typeof(NullableClass6), "Field1", false, true)] + [InlineData(typeof(NullableClass6), "Field2", false, true)] + [InlineData(typeof(NullableClass7), "Field1", false, false)] + [InlineData(typeof(NullableClass7), "Field2", false, false)] + [InlineData(typeof(NullableClass7), "Field3", false, true)] + [InlineData(typeof(NullableClass8), "Field1", false, false)] + [InlineData(typeof(NullableClass8), "Field2", false, false)] + [InlineData(typeof(NullableClass8), "Field3", false, true)] + [InlineData(typeof(NullableClass8), "Field4", false, false)] + [InlineData(typeof(NullableClass9), "Field1", true, true)] + [InlineData(typeof(NullableClass10), "Field1", true, true)] + [InlineData(typeof(NullableClass11), "Field1", false, false)] + [InlineData(typeof(NullableClass11), "Field2", true, false)] + [InlineData(typeof(NullableClass12), "Field1", false, true)] + [InlineData(typeof(NullableClass12), "Field2", true, false)] + [InlineData(typeof(NullableClass12), "Field3", true, false)] + [InlineData(typeof(NullableClass12), "Field4", false, true)] + [InlineData(typeof(NullableClass13), "Field1", false, false)] + [InlineData(typeof(NullableClass13), "Field2", false, false)] + [InlineData(typeof(NullableClass14), "Field1", false, false)] + [InlineData(typeof(NullableClass14), "Field2", false, false)] + [InlineData(typeof(NullableClass15), "Field1", false, true)] + [InlineData(typeof(NullableClass15), "Field2", true, false)] + [InlineData(typeof(NullableClass15), "Field3", true, false)] + [InlineData(typeof(NullableClass15), "Field4", false, true)] public void VerifyTestMethod(Type type, string methodName, bool hasNullable, bool hasNullableContext) { var method = type.GetMethod(methodName); @@ -101,23 +100,23 @@ public void VerifyTestMethod(Type type, string methodName, bool hasNullable, boo actualHasNullableContext.ShouldBe(hasNullableContext); } - [DataTestMethod] - [DataRow(typeof(NullableClass9), "Field1", "arg1", false)] - [DataRow(typeof(NullableClass9), "Field1", "arg2", false)] - [DataRow(typeof(NullableClass10), "Field1", "arg1", false)] - [DataRow(typeof(NullableClass10), "Field1", "arg2", false)] - [DataRow(typeof(NullableClass11), "Field2", "arg1", false)] - [DataRow(typeof(NullableClass11), "Field2", "arg2", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg1", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg2", true)] - [DataRow(typeof(NullableClass13), "Field2", "arg3", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg4", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg5", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg1", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg2", true)] - [DataRow(typeof(NullableClass14), "Field2", "arg3", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg4", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg5", false)] + [Theory] + [InlineData(typeof(NullableClass9), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass9), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg4", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg5", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg4", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] public void VerifyTestArgument(Type type, string methodName, string argumentName, bool hasNullable) { var method = type.GetMethod(methodName); @@ -127,51 +126,51 @@ public void VerifyTestArgument(Type type, string methodName, string argumentName actualHasNullable.ShouldBe(hasNullable); } - [DataTestMethod] - [DataRow(typeof(NullableClass1), "Field1", true)] - [DataRow(typeof(NullableClass1), "Field2", false)] - [DataRow(typeof(NullableClass1), "Field3", false)] - [DataRow(typeof(NullableClass1), "Field4", true)] - [DataRow(typeof(NullableClass1), "Field5", true)] - [DataRow(typeof(NullableClass1), "Field6", false)] - [DataRow(typeof(NullableClass1), "Field7", false)] - [DataRow(typeof(NullableClass1), "Field8", true)] - [DataRow(typeof(NullableClass2), "Field1", true)] - [DataRow(typeof(NullableClass2), "Field2", false)] - [DataRow(typeof(NullableClass2), "Field3", false)] - [DataRow(typeof(NullableClass2), "Field4", true)] - [DataRow(typeof(NullableClass2), "Field5", true)] - [DataRow(typeof(NullableClass2), "Field6", false)] - [DataRow(typeof(NullableClass2), "Field7", true)] - [DataRow(typeof(NullableClass2), "Field8", true)] - [DataRow(typeof(NullableClass2), "Field9", false)] - [DataRow(typeof(NullableClass2), "Field10", true)] - [DataRow(typeof(NullableClass5), "Test", false)] - [DataRow(typeof(NullableClass6), "Field1", false)] - [DataRow(typeof(NullableClass6), "Field2", true)] - [DataRow(typeof(NullableClass7), "Field1", false)] - [DataRow(typeof(NullableClass7), "Field2", false)] - [DataRow(typeof(NullableClass7), "Field3", true)] - [DataRow(typeof(NullableClass8), "Field1", true)] - [DataRow(typeof(NullableClass8), "Field2", true)] - [DataRow(typeof(NullableClass8), "Field3", false)] - [DataRow(typeof(NullableClass8), "Field4", false)] - [DataRow(typeof(NullableClass9), "Field1", false)] - [DataRow(typeof(NullableClass10), "Field1", true)] - [DataRow(typeof(NullableClass11), "Field1", false)] - [DataRow(typeof(NullableClass11), "Field2", true)] - [DataRow(typeof(NullableClass12), "Field1", false)] - [DataRow(typeof(NullableClass12), "Field2", true)] - [DataRow(typeof(NullableClass12), "Field3", true)] - [DataRow(typeof(NullableClass12), "Field4", true)] - [DataRow(typeof(NullableClass13), "Field1", false)] - [DataRow(typeof(NullableClass13), "Field2", false)] - [DataRow(typeof(NullableClass14), "Field1", true)] - [DataRow(typeof(NullableClass14), "Field2", true)] - [DataRow(typeof(NullableClass15), "Field1", false)] - [DataRow(typeof(NullableClass15), "Field2", true)] - [DataRow(typeof(NullableClass15), "Field3", true)] - [DataRow(typeof(NullableClass15), "Field4", true)] + [Theory] + [InlineData(typeof(NullableClass1), "Field1", true)] + [InlineData(typeof(NullableClass1), "Field2", false)] + [InlineData(typeof(NullableClass1), "Field3", false)] + [InlineData(typeof(NullableClass1), "Field4", true)] + [InlineData(typeof(NullableClass1), "Field5", true)] + [InlineData(typeof(NullableClass1), "Field6", false)] + [InlineData(typeof(NullableClass1), "Field7", false)] + [InlineData(typeof(NullableClass1), "Field8", true)] + [InlineData(typeof(NullableClass2), "Field1", true)] + [InlineData(typeof(NullableClass2), "Field2", false)] + [InlineData(typeof(NullableClass2), "Field3", false)] + [InlineData(typeof(NullableClass2), "Field4", true)] + [InlineData(typeof(NullableClass2), "Field5", true)] + [InlineData(typeof(NullableClass2), "Field6", false)] + [InlineData(typeof(NullableClass2), "Field7", true)] + [InlineData(typeof(NullableClass2), "Field8", true)] + [InlineData(typeof(NullableClass2), "Field9", false)] + [InlineData(typeof(NullableClass2), "Field10", true)] + [InlineData(typeof(NullableClass5), "Test", false)] + [InlineData(typeof(NullableClass6), "Field1", false)] + [InlineData(typeof(NullableClass6), "Field2", true)] + [InlineData(typeof(NullableClass7), "Field1", false)] + [InlineData(typeof(NullableClass7), "Field2", false)] + [InlineData(typeof(NullableClass7), "Field3", true)] + [InlineData(typeof(NullableClass8), "Field1", true)] + [InlineData(typeof(NullableClass8), "Field2", true)] + [InlineData(typeof(NullableClass8), "Field3", false)] + [InlineData(typeof(NullableClass8), "Field4", false)] + [InlineData(typeof(NullableClass9), "Field1", false)] + [InlineData(typeof(NullableClass10), "Field1", true)] + [InlineData(typeof(NullableClass11), "Field1", false)] + [InlineData(typeof(NullableClass11), "Field2", true)] + [InlineData(typeof(NullableClass12), "Field1", false)] + [InlineData(typeof(NullableClass12), "Field2", true)] + [InlineData(typeof(NullableClass12), "Field3", true)] + [InlineData(typeof(NullableClass12), "Field4", true)] + [InlineData(typeof(NullableClass13), "Field1", false)] + [InlineData(typeof(NullableClass13), "Field2", false)] + [InlineData(typeof(NullableClass14), "Field1", true)] + [InlineData(typeof(NullableClass14), "Field2", true)] + [InlineData(typeof(NullableClass15), "Field1", false)] + [InlineData(typeof(NullableClass15), "Field2", true)] + [InlineData(typeof(NullableClass15), "Field3", true)] + [InlineData(typeof(NullableClass15), "Field4", true)] public void Method(Type type, string methodName, bool expected) { var method = type.GetMethod(methodName); @@ -179,23 +178,23 @@ public void Method(Type type, string methodName, bool expected) nullable.ShouldBe(expected); } - [DataTestMethod] - [DataRow(typeof(NullableClass9), "Field1", "arg1", true)] - [DataRow(typeof(NullableClass9), "Field1", "arg2", true)] - [DataRow(typeof(NullableClass10), "Field1", "arg1", false)] - [DataRow(typeof(NullableClass10), "Field1", "arg2", false)] - [DataRow(typeof(NullableClass11), "Field2", "arg1", false)] - [DataRow(typeof(NullableClass11), "Field2", "arg2", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg1", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg2", true)] - [DataRow(typeof(NullableClass13), "Field2", "arg3", false)] - [DataRow(typeof(NullableClass13), "Field2", "arg4", true)] - [DataRow(typeof(NullableClass13), "Field2", "arg5", true)] - [DataRow(typeof(NullableClass14), "Field2", "arg1", true)] - [DataRow(typeof(NullableClass14), "Field2", "arg2", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg3", false)] - [DataRow(typeof(NullableClass14), "Field2", "arg4", true)] - [DataRow(typeof(NullableClass14), "Field2", "arg5", false)] + [Theory] + [InlineData(typeof(NullableClass9), "Field1", "arg1", true)] + [InlineData(typeof(NullableClass9), "Field1", "arg2", true)] + [InlineData(typeof(NullableClass10), "Field1", "arg1", false)] + [InlineData(typeof(NullableClass10), "Field1", "arg2", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass11), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg1", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg2", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass13), "Field2", "arg4", true)] + [InlineData(typeof(NullableClass13), "Field2", "arg5", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg1", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg2", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg3", false)] + [InlineData(typeof(NullableClass14), "Field2", "arg4", true)] + [InlineData(typeof(NullableClass14), "Field2", "arg5", false)] public void Argument(Type type, string methodName, string argumentName, bool expected) { var method = type.GetMethod(methodName); diff --git a/src/Tests/DIObjectGraphTypeTests/Services.cs b/src/Tests/DIObjectGraphTypeTests/Services.cs index cef2120..c367217 100644 --- a/src/Tests/DIObjectGraphTypeTests/Services.cs +++ b/src/Tests/DIObjectGraphTypeTests/Services.cs @@ -1,15 +1,16 @@ using System; +using System.ComponentModel; using System.Threading.Tasks; using GraphQL.DI; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using GraphQL.Types; using Shouldly; +using Xunit; namespace DIObjectGraphTypeTests { - [TestClass] public class Services : DIObjectGraphTypeTestBase { - [TestMethod] + [Fact] public void Service() { Configure(); @@ -23,7 +24,7 @@ public class CService : DIObjectGraphBase public static string Field1([FromServices] string arg) => arg; } - [TestMethod] + [Fact] public void ServiceMissingThrows() { Configure(); @@ -32,7 +33,7 @@ public void ServiceMissingThrows() Verify(false); } - [TestMethod] + [Fact] public async Task ScopedService() { Configure(); diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 23f44a9..118d0fb 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -16,8 +16,11 @@ - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + all runtime; build; native; contentfiles; analyzers; buildtransitive From eef000e0b76cf4fd044f63fdb0eeabad013ee84e Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 17:54:51 -0400 Subject: [PATCH 24/31] Update readme with coveralls link --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fd7324..a8b5a5c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # GraphQL.DI -[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) +[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status] +(https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) From f4d44d4788c993bba4046c2062227144bd9e42b5 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 18:13:55 -0400 Subject: [PATCH 25/31] Add more tests --- src/Tests/Execution/DIDocumentExecuter.cs | 102 ++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/Tests/Execution/DIDocumentExecuter.cs diff --git a/src/Tests/Execution/DIDocumentExecuter.cs b/src/Tests/Execution/DIDocumentExecuter.cs new file mode 100644 index 0000000..6a93455 --- /dev/null +++ b/src/Tests/Execution/DIDocumentExecuter.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Text; +using GraphQL.DI; +using GraphQL.Execution; +using GraphQL.Language.AST; +using GraphQL.Validation; +using GraphQL.Validation.Complexity; +using Moq; +using Shouldly; +using Xunit; + +namespace Execution +{ + public class DIDocumentExecuterTests + { + [Fact] + public void CreateWithDefaults() + { + var test = new MockDIDocumentExecuter(); + test.TestSelectExecutionStrategy(OperationType.Query).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Mutation).ShouldBeOfType(); + Should.Throw(() => test.TestSelectExecutionStrategy(OperationType.Subscription)); + } + + [Fact] + public void CreateWithSubscription() + { + var strategy = new ParallelExecutionStrategy(); + var test = new MockDIDocumentExecuter(strategy); + test.TestSelectExecutionStrategy(OperationType.Query).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Mutation).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Subscription).ShouldBe(strategy); + } + + [Fact] + public void CreateWithServiceProviderDefaults() + { + var serviceProviderMock = new Mock(MockBehavior.Strict); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentBuilder))).Returns((IDocumentBuilder)null).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentValidator))).Returns((IDocumentValidator)null).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IComplexityAnalyzer))).Returns((IComplexityAnalyzer)null).Verifiable(); + var test = new MockDIDocumentExecuter(serviceProviderMock.Object); + test.TestSelectExecutionStrategy(OperationType.Query).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Mutation).ShouldBeOfType(); + Should.Throw(() => test.TestSelectExecutionStrategy(OperationType.Subscription)); + } + + [Fact] + public void CreateWithServiceProviderInstances() + { + var documentBuilder = new Mock(MockBehavior.Strict).Object; + var documentValidator = new Mock(MockBehavior.Strict).Object; + var complexityAnalyzer = new Mock(MockBehavior.Strict).Object; + var serviceProviderMock = new Mock(MockBehavior.Strict); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentBuilder))).Returns(documentBuilder).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentValidator))).Returns(documentValidator).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IComplexityAnalyzer))).Returns(complexityAnalyzer).Verifiable(); + var test = new MockDIDocumentExecuter(serviceProviderMock.Object); + test.TestSelectExecutionStrategy(OperationType.Query).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Mutation).ShouldBeOfType(); + Should.Throw(() => test.TestSelectExecutionStrategy(OperationType.Subscription)); + } + + [Fact] + public void CreateWithServiceProviderDefaultsAndSubscription() + { + var serviceProviderMock = new Mock(MockBehavior.Strict); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentBuilder))).Returns((IDocumentBuilder)null).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IDocumentValidator))).Returns((IDocumentValidator)null).Verifiable(); + serviceProviderMock.Setup(x => x.GetService(typeof(IComplexityAnalyzer))).Returns((IComplexityAnalyzer)null).Verifiable(); + var strategy = new ParallelExecutionStrategy(); + var test = new MockDIDocumentExecuter(serviceProviderMock.Object, strategy); + test.TestSelectExecutionStrategy(OperationType.Query).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Mutation).ShouldBeOfType(); + test.TestSelectExecutionStrategy(OperationType.Subscription).ShouldBe(strategy); + } + + [Fact] + public void UnknownOperationType() + { + var obj = new MockDIDocumentExecuter(); + Should.Throw(() => obj.TestSelectExecutionStrategy((OperationType)255)); + } + + private class MockDIDocumentExecuter : DIDocumentExecuter + { + public MockDIDocumentExecuter() : base() { } + public MockDIDocumentExecuter(IExecutionStrategy executionStrategy) : base(executionStrategy) { } + public MockDIDocumentExecuter(IServiceProvider serviceProvider) : base(serviceProvider) { } + public MockDIDocumentExecuter(IServiceProvider serviceProvider, IExecutionStrategy executionStrategy) : base(serviceProvider, executionStrategy) { } + + public IExecutionStrategy TestSelectExecutionStrategy(OperationType operationType) + { + var context = new ExecutionContext(); + context.Operation = new Operation(new NameNode("test")); + context.Operation.OperationType = operationType; + return base.SelectExecutionStrategy(context); + } + } + } +} From 6d460fcf02cd5f08f444d75e0b22f5218479bde1 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 18:14:34 -0400 Subject: [PATCH 26/31] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index a8b5a5c..9caa4ac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ # GraphQL.DI -[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status] -(https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) +[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status] (https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) From 06f94173f86c134fc0eef4e9f771327fd448975c Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 18:15:20 -0400 Subject: [PATCH 27/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9caa4ac..f6b589c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # GraphQL.DI -[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status] (https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) +[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status](https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) From 7ea1d6bda61435974a42fbd3fcfcf55197d0d98f Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 23 Mar 2021 18:16:50 -0400 Subject: [PATCH 28/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6b589c..55b25c6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # GraphQL.DI -[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status](https://coveralls.io/repos/github/Shane32/ExcelLinq/badge.svg?branch=master)](https://coveralls.io/github/Shane32/ExcelLinq?branch=master) +[![NuGet](https://img.shields.io/nuget/v/Shane32.GraphQL.DI.svg)](https://www.nuget.org/packages/Shane32.GraphQL.DI) [![Coverage Status](https://coveralls.io/repos/github/Shane32/GraphQL.DI/badge.svg?branch=master)](https://coveralls.io/github/Shane32/GraphQL.DI?branch=master) From c3cc13967f1a43d265f25baa19fa127af7ada82a Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 19:00:27 -0400 Subject: [PATCH 29/31] Added more tests --- src/GraphQL.DI/DIObjectGraphType.cs | 82 +++++++------------ src/Tests/DIObjectGraphTypeTests/Argument.cs | 62 ++++++++++++++ .../DIObjectGraphTypeTestBase.cs | 15 +++- src/Tests/DIObjectGraphTypeTests/Field.cs | 75 +++++++++++++++++ 4 files changed, 181 insertions(+), 53 deletions(-) diff --git a/src/GraphQL.DI/DIObjectGraphType.cs b/src/GraphQL.DI/DIObjectGraphType.cs index ba754ac..4105d93 100644 --- a/src/GraphQL.DI/DIObjectGraphType.cs +++ b/src/GraphQL.DI/DIObjectGraphType.cs @@ -248,29 +248,10 @@ protected virtual bool GetNullability(MethodInfo method) if (method.ReturnType.IsValueType) return method.ReturnType.IsConstructedGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Nullable<>); - Nullability nullable = Nullability.Unknown; - - // check the parent type first to see if there's a nullable context attribute set for it - var parentType = method.DeclaringType; - var attribute = parentType.CustomAttributes.FirstOrDefault(x => - x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && - x.ConstructorArguments.Count == 1 && - x.ConstructorArguments[0].ArgumentType == typeof(byte)); - if (attribute != null) { - nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; - } - - // now check the method to see if there's a nullable context attribute set for it - attribute = method.CustomAttributes.FirstOrDefault(x => - x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute" && - x.ConstructorArguments.Count == 1 && - x.ConstructorArguments[0].ArgumentType == typeof(byte)); - if (attribute != null) { - nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; - } + Nullability nullable = GetMethodDefaultNullability(method); // now check the return type to see if there's a nullable attribute for it - attribute = method.ReturnParameter.CustomAttributes.FirstOrDefault(x => + var attribute = method.ReturnParameter.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute" && x.ConstructorArguments.Count == 1 && (x.ConstructorArguments[0].ArgumentType == typeof(byte) || @@ -312,21 +293,9 @@ private enum Nullability : byte Nullable = 2, } - /// - /// Returns a boolean indicating if the parameter value is nullable - /// - protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter) + private Nullability GetMethodDefaultNullability(MethodInfo method) { - if (parameter.GetCustomAttribute() != null) - return true; - if (parameter.GetCustomAttribute() != null) - return false; - if (parameter.GetCustomAttribute() != null) - return false; - if (parameter.ParameterType.IsValueType) - return parameter.ParameterType.IsConstructedGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>); - - Nullability nullable = Nullability.Unknown; + var nullable = Nullability.Unknown; // check the parent type first to see if there's a nullable context attribute set for it var parentType = method.DeclaringType; @@ -347,8 +316,29 @@ protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter nullable = (Nullability)(byte)attribute.ConstructorArguments[0].Value; } + return nullable; + } + + /// + /// Returns a boolean indicating if the parameter value is nullable + /// + protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter) + { + if (parameter.GetCustomAttribute() != null) + return true; + if (parameter.GetCustomAttribute() != null) + return false; + if (parameter.GetCustomAttribute() != null) + return false; + if (parameter.IsOptional) + return true; + if (parameter.ParameterType.IsValueType) + return parameter.ParameterType.IsConstructedGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>); + + Nullability nullable = GetMethodDefaultNullability(method); + // now check the parameter to see if there's a nullable attribute for it - attribute = parameter.CustomAttributes.FirstOrDefault(x => + var attribute = parameter.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute" && x.ConstructorArguments.Count == 1 && (x.ConstructorArguments[0].ArgumentType == typeof(byte) || @@ -358,23 +348,11 @@ protected virtual bool GetNullability(MethodInfo method, ParameterInfo parameter } var nullabilityBytes = attribute?.ConstructorArguments[0].Value as byte[]; - var index = 0; - nullable = Consider(parameter.ParameterType); + if ((nullabilityBytes != null && nullabilityBytes[0] == (byte)Nullability.Nullable) || (nullabilityBytes == null && nullable == Nullability.Nullable)) + return true; + if (nullabilityBytes != null) + return (Nullability)nullabilityBytes[0] != Nullability.NonNullable; return nullable != Nullability.NonNullable; - - Nullability Consider(Type t) - { - var g = t.IsGenericType ? t.GetGenericTypeDefinition() : null; - if (g == typeof(Nullable<>)) - return Nullability.Nullable; - if (t.IsValueType) - return Nullability.NonNullable; - if ((nullabilityBytes != null && nullabilityBytes[index] == (byte)Nullability.Nullable) || (nullabilityBytes == null && nullable == Nullability.Nullable)) - return Nullability.Nullable; - if (nullabilityBytes != null) - return (Nullability)nullabilityBytes[index]; - return nullable; - } } /// diff --git a/src/Tests/DIObjectGraphTypeTests/Argument.cs b/src/Tests/DIObjectGraphTypeTests/Argument.cs index 9c13ce4..19fd785 100644 --- a/src/Tests/DIObjectGraphTypeTests/Argument.cs +++ b/src/Tests/DIObjectGraphTypeTests/Argument.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Threading; using GraphQL.DI; using GraphQL.Types; using Shouldly; @@ -78,6 +79,20 @@ public class CNonNullableObject : DIObjectGraphBase public static string Field1([Required] string arg) => arg; } + [Fact] + public void NonNullableObject2() + { + Configure(); + VerifyFieldArgument("Field1", "arg", false, "hello"); + VerifyField("Field1", true, false, "hello"); + Verify(false); + } + + public class CNonNullableObject2 : DIObjectGraphBase + { + public static string Field1([System.ComponentModel.DataAnnotations.Required] string arg) => arg; + } + [Fact] public void Name() { @@ -121,5 +136,52 @@ public class CGraphType : DIObjectGraphBase public static string Field1([GraphType(typeof(StringGraphType))] string arg) => arg; } + [Fact] + public void CancellationToken() + { + using var cts = new CancellationTokenSource(); + var token = cts.Token; + cts.Cancel(); + Configure(); + _contextMock.SetupGet(x => x.CancellationToken).Returns(token).Verifiable(); + VerifyField("Field1", true, false, "hello + True"); + Verify(false); + } + + public class CCancellationToken : DIObjectGraphBase + { + public static string Field1(CancellationToken cancellationToken) => "hello + " + cancellationToken.IsCancellationRequested; + } + + [Fact] + public void NullNameArgument() + { + Configure(); + VerifyField("Field1", true, false, "hello + 0"); + Verify(false); + } + + public class CNullNameArgument : DIObjectGraphBase + { + public static string Field1([Name(null)] int arg) => "hello + " + arg; + } + + [Fact] + public void DefaultValue() + { + Configure(); + VerifyFieldArgument("Field1", "arg1", true, 2); + VerifyField("Field1", false, false, 2); + VerifyFieldArgument("Field2", "arg2", true); + VerifyField("Field2", false, false, 5); + Verify(false); + } + + public class CDefaultValue : DIObjectGraphBase + { + public static int Field1(int arg1 = 4) => arg1; + public static int Field2(int arg2 = 5) => arg2; + } + } } diff --git a/src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs b/src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs index 242d61f..56cf151 100644 --- a/src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs +++ b/src/Tests/DIObjectGraphTypeTests/DIObjectGraphTypeTestBase.cs @@ -70,6 +70,7 @@ protected FieldType VerifyField(string fieldName, Type fieldGraphType, bool c field.Resolver.ShouldNotBeNull(); _contextMock.Setup(x => x.FieldDefinition).Returns(field); field.Resolver.Resolve(context).ShouldBe(returnValue); + _arguments.Clear(); return field; } @@ -88,6 +89,7 @@ protected async Task VerifyFieldAsync(string fieldName, bool nulla var taskRet = ret.ShouldBeOfType>(); var final = await taskRet; final.ShouldBe(returnValue); + _arguments.Clear(); return field; } @@ -96,7 +98,12 @@ protected QueryArgument VerifyFieldArgument(string fieldName, string argument return VerifyFieldArgument(fieldName, argumentName, typeof(T).GetGraphTypeFromType(nullable, TypeMappingMode.InputType), returnValue); } - protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, Type graphType, T returnValue) + protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, bool nullable) + { + return VerifyFieldArgument(fieldName, argumentName, typeof(T).GetGraphTypeFromType(nullable, TypeMappingMode.InputType)); + } + + protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, Type graphType) { _graphType.ShouldNotBeNull(); _graphType.Fields.ShouldNotBeNull(); @@ -106,6 +113,12 @@ protected QueryArgument VerifyFieldArgument(string fieldName, string argument var argument = field.Arguments.Find(argumentName); argument.ShouldNotBeNull(); argument.Type.ShouldBe(graphType); + return argument; + } + + protected QueryArgument VerifyFieldArgument(string fieldName, string argumentName, Type graphType, T returnValue) + { + var argument = VerifyFieldArgument(fieldName, argumentName, graphType); _arguments.Add(argumentName, new ArgumentValue(returnValue, ArgumentSource.FieldDefault)); return argument; } diff --git a/src/Tests/DIObjectGraphTypeTests/Field.cs b/src/Tests/DIObjectGraphTypeTests/Field.cs index 089f5e8..1c72d8e 100644 --- a/src/Tests/DIObjectGraphTypeTests/Field.cs +++ b/src/Tests/DIObjectGraphTypeTests/Field.cs @@ -402,6 +402,81 @@ public class CInheritedConcurrentOverridable : DIObjectGraphBase public static Task Field1(IServiceProvider services) => Task.FromResult("hello"); } + [Fact] + public async Task RemoveAsyncFromName() + { + Configure(); + await VerifyFieldAsync("Field1", true, true, "hello"); + Verify(false); + } + + public class CRemoveAsyncFromName : DIObjectGraphBase + { + public static Task Field1Async() => Task.FromResult("hello"); + } + + [Fact] + public void SkipVoidMembers() + { + Configure(); + _graphType.Fields.Find("Field1").ShouldBeNull(); + _graphType.Fields.Find("Field2").ShouldBeNull(); + } + + public class CSkipVoidMembers : DIObjectGraphBase + { + public static Task Field1() => Task.CompletedTask; + public static void Field2() { } + } + + [Fact] + public void SkipNullName() + { + Configure(); + _graphType.Fields.Find("Field1").ShouldBeNull(); + } + + public class CSkipNullName : DIObjectGraphBase + { + [Name(null)] + public static string Field1() => "hello"; + } + + [Fact] + public void AddsMetadata() + { + Configure(); + var field = VerifyField("Field1", true, false, "hello"); + field.GetMetadata("test").ShouldBe("value"); + Verify(false); + } + + public class CAddsMetadata : DIObjectGraphBase + { + [Metadata("test", "value")] + public static string Field1() => "hello"; + } + + [Fact] + public void AddsInheritedMetadata() + { + Configure(); + var field = VerifyField("Field1", true, false, "hello"); + field.GetMetadata("test").ShouldBe("value2"); + Verify(false); + } + + public class CAddsInheritedMetadata : DIObjectGraphBase + { + [InheritedMetadata("value2")] + public static string Field1() => "hello"; + } + + private class InheritedMetadata : MetadataAttribute + { + public InheritedMetadata(string value) : base("test", value) { } + } + [Theory] [InlineData("Field1", typeof(GraphQLClrOutputTypeReference))] [InlineData("Field2", typeof(NonNullGraphType>))] From 55735e030146cf41b45e651997e0f64c4bd23f55 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 19:21:57 -0400 Subject: [PATCH 30/31] Basic execution strategy test --- src/Tests/DIObjectGraphTypeTests/Argument.cs | 3 +- src/Tests/Execution/DIDocumentExecuter.cs | 8 ++- src/Tests/Execution/DIDocumentStrategy.cs | 57 ++++++++++++++++++++ src/Tests/Tests.csproj | 2 + 4 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 src/Tests/Execution/DIDocumentStrategy.cs diff --git a/src/Tests/DIObjectGraphTypeTests/Argument.cs b/src/Tests/DIObjectGraphTypeTests/Argument.cs index 19fd785..11c70b0 100644 --- a/src/Tests/DIObjectGraphTypeTests/Argument.cs +++ b/src/Tests/DIObjectGraphTypeTests/Argument.cs @@ -157,7 +157,8 @@ public class CCancellationToken : DIObjectGraphBase public void NullNameArgument() { Configure(); - VerifyField("Field1", true, false, "hello + 0"); + var field = VerifyField("Field1", true, false, "hello + 0"); + field.Arguments.Count.ShouldBe(0); Verify(false); } diff --git a/src/Tests/Execution/DIDocumentExecuter.cs b/src/Tests/Execution/DIDocumentExecuter.cs index 6a93455..412e6f0 100644 --- a/src/Tests/Execution/DIDocumentExecuter.cs +++ b/src/Tests/Execution/DIDocumentExecuter.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using GraphQL.DI; using GraphQL.Execution; using GraphQL.Language.AST; @@ -83,6 +81,12 @@ public void UnknownOperationType() Should.Throw(() => obj.TestSelectExecutionStrategy((OperationType)255)); } + [Fact] + public void NullServiceProviderThrows() + { + Should.Throw(() => new DIDocumentExecuter((IServiceProvider)null)); + } + private class MockDIDocumentExecuter : DIDocumentExecuter { public MockDIDocumentExecuter() : base() { } diff --git a/src/Tests/Execution/DIDocumentStrategy.cs b/src/Tests/Execution/DIDocumentStrategy.cs new file mode 100644 index 0000000..d0ac5f4 --- /dev/null +++ b/src/Tests/Execution/DIDocumentStrategy.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading.Tasks; +using GraphQL; +using GraphQL.DataLoader; +using GraphQL.DI; +using GraphQL.Execution; +using GraphQL.Language.AST; +using GraphQL.SystemTextJson; +using GraphQL.Types; +using GraphQL.Validation; +using GraphQL.Validation.Complexity; +using Moq; +using Shouldly; +using Xunit; + +namespace Execution +{ + public class DIDocumentStrategyTests + { + private readonly IDocumentExecuter _executer = new DIDocumentExecuter(); + private readonly ISchema _schema = new MySchema(); + private readonly IDocumentWriter _writer = new DocumentWriter(false); + + [Fact] + public async Task ItRuns() + { + var result = await _executer.ExecuteAsync(new GraphQL.ExecutionOptions { + Query = "{field1,field2,field3,field4,field5,field6,field7,field8}", + Schema = _schema, + MaxParallelExecutionCount = 2, + }); + result.Errors.ShouldBeNull(); + var resultString = await _writer.WriteToStringAsync(result); + resultString.ShouldBe(@"{""data"":{""field1"":""ret1"",""field2"":""ret2"",""field3"":""ret3"",""field4"":""ret4"",""field5"":""ret5"",""field6"":""ret6"",""field7"":""ret7"",""field8"":""ret8""}}"); + } + + private class MySchema : Schema + { + public MySchema() + { + Query = new DIObjectGraphType(); + } + } + + private class Graph1 : DIObjectGraphBase + { + public static string Field1() => "ret1"; + public static Task Field2() => Task.FromResult("ret2"); + public static Task Field3() => Task.FromResult("ret3"); + public static string Field4() => "ret4"; + public static async Task Field5() { await Task.Yield(); return "ret5"; } + public static async Task Field6() { await Task.Yield(); return "ret6"; } + public static async Task Field7() { await Task.Yield(); return "ret7"; } + public static IDataLoaderResult Field8() => new SimpleDataLoader(c => Task.FromResult("ret8")); + } + } +} diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 118d0fb..9867ab8 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -13,6 +13,8 @@ + + From 1f12b5228be2955398524ca69f6a59f263cdfd26 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Tue, 23 Mar 2021 19:24:16 -0400 Subject: [PATCH 31/31] Cleanup --- src/Tests/Execution/DIDocumentStrategy.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Tests/Execution/DIDocumentStrategy.cs b/src/Tests/Execution/DIDocumentStrategy.cs index d0ac5f4..1b9f6fc 100644 --- a/src/Tests/Execution/DIDocumentStrategy.cs +++ b/src/Tests/Execution/DIDocumentStrategy.cs @@ -1,15 +1,9 @@ -using System; using System.Threading.Tasks; using GraphQL; using GraphQL.DataLoader; using GraphQL.DI; -using GraphQL.Execution; -using GraphQL.Language.AST; using GraphQL.SystemTextJson; using GraphQL.Types; -using GraphQL.Validation; -using GraphQL.Validation.Complexity; -using Moq; using Shouldly; using Xunit; @@ -23,15 +17,20 @@ public class DIDocumentStrategyTests [Fact] public async Task ItRuns() + { + var actual = await RunQuery("{field1,field2,field3,field4,field5,field6,field7,field8}"); + actual.ShouldBe(@"{""data"":{""field1"":""ret1"",""field2"":""ret2"",""field3"":""ret3"",""field4"":""ret4"",""field5"":""ret5"",""field6"":""ret6"",""field7"":""ret7"",""field8"":""ret8""}}"); + } + + private async Task RunQuery(string query) { var result = await _executer.ExecuteAsync(new GraphQL.ExecutionOptions { - Query = "{field1,field2,field3,field4,field5,field6,field7,field8}", + Query = query, Schema = _schema, MaxParallelExecutionCount = 2, }); result.Errors.ShouldBeNull(); - var resultString = await _writer.WriteToStringAsync(result); - resultString.ShouldBe(@"{""data"":{""field1"":""ret1"",""field2"":""ret2"",""field3"":""ret3"",""field4"":""ret4"",""field5"":""ret5"",""field6"":""ret6"",""field7"":""ret7"",""field8"":""ret8""}}"); + return await _writer.WriteToStringAsync(result); } private class MySchema : Schema