diff --git a/src/Core/Abstractions.Tests/ErrorBuilderTests.cs b/src/Core/Abstractions.Tests/ErrorBuilderTests.cs new file mode 100644 index 00000000000..047553d9a25 --- /dev/null +++ b/src/Core/Abstractions.Tests/ErrorBuilderTests.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Xunit; + +namespace HotChocolate +{ + public class ErrorBuilderTests + { + [Fact] + public void FromError() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + ErrorBuilder builder = ErrorBuilder.FromError(error); + error = builder.Build(); + + // assert + Assert.Equal("123", error.Message); + } + + [Fact] + public void FromError_WithExtensions() + { + // arrange + IError error = new Error + { + Message = "123", + Extensions = ImmutableDictionary + .Empty + .Add("foo", "bar") + }; + + // act + ErrorBuilder builder = ErrorBuilder.FromError(error); + error = builder.Build(); + + // assert + Assert.Equal("123", error.Message); + Assert.Collection(error.Extensions, + t => Assert.Equal("bar", t.Value)); + } + + [Fact] + public void FromError_WithLocations() + { + // arrange + IError error = new Error + { + Message = "123", + Locations = ImmutableList + .Empty + .Add(new Location(1, 2)) + }; + + // act + ErrorBuilder builder = ErrorBuilder.FromError(error); + error = builder.Build(); + + // assert + Assert.Equal("123", error.Message); + Assert.Collection(error.Locations, + t => Assert.Equal(1, t.Line)); + } + + [Fact] + public void FromError_ErrorNull_ArgumentNullException() + { + // arrange + // act + Action action = () => ErrorBuilder.FromError(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void SetMessage_MessageNull_ArgumentException() + { + // arrange + // act + Action action = () => ErrorBuilder.New().SetMessage(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void SetMessage_Bar_ErrorCodeIsFoo() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .Build(); + + // assert + Assert.Equal("bar", error.Message); + } + + [Fact] + public void SetCode_Foo_ErrorCodeIsFoo() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .SetCode("foo") + .Build(); + + // assert + Assert.Equal("foo", error.Code); + Assert.Collection(error.Extensions, + t => Assert.Equal("foo", t.Value)); + } + + [Fact] + public void SetPath_Foo_PathIsFooWithCount1() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .SetPath(new List { "foo" }) + .Build(); + + // assert + Assert.Collection(error.Path, + t => Assert.Equal("foo", t.ToString())); + } + + [Fact] + public void SetPathObject_Foo_PathIsFooWithCount1() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .SetPath(Path.New("foo")) + .Build(); + + // assert + Assert.Collection(error.Path, + t => Assert.Equal("foo", t.ToString())); + } + + [Fact] + public void AddLocation() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .AddLocation(new Location(2, 3)) + .Build(); + + // assert + Assert.Collection(error.Locations, + t => Assert.Equal(2, t.Line)); + } + + [Fact] + public void AddLocation2() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .AddLocation(new Location(2, 3)) + .AddLocation(new Location(4, 5)) + .Build(); + + // assert + Assert.Collection(error.Locations, + t => Assert.Equal(2, t.Line), + t => Assert.Equal(4, t.Line)); + } + + [Fact] + public void AddLocation3() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .AddLocation(2, 3) + .AddLocation(new Location(4, 5)) + .Build(); + + // assert + Assert.Collection(error.Locations, + t => Assert.Equal(2, t.Line), + t => Assert.Equal(4, t.Line)); + } + + [Fact] + public void AddLocation_LineSmallerThan1_ArgumentException() + { + // arrange + // act + Action action = () => ErrorBuilder.New() + .AddLocation(0, 3); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddLocation_ColumnSmallerThan1_ArgumentException() + { + // arrange + // act + Action action = () => ErrorBuilder.New() + .AddLocation(2, 0); + + // assert + Assert.Throws(action); + } + + [Fact] + public void SetException() + { + // arrange + var exception = new Exception(); + + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .SetException(exception) + .Build(); + + // assert + Assert.Equal(exception, error.Exception); + } + + [Fact] + public void SetExtension() + { + // arrange + // act + IError error = ErrorBuilder.New() + .SetMessage("bar") + .SetExtension("a", "b") + .SetExtension("a", "c") + .SetExtension("c", "d") + .Build(); + + // assert + Assert.Collection(error.Extensions.OrderBy(t => t.Key), + t => Assert.Equal("c", t.Value), + t => Assert.Equal("d", t.Value)); + } + + [Fact] + public void Build_NoMessage_InvalidOperationException() + { + // arrange + // act + Action action = () => ErrorBuilder.New().Build(); + + // assert + Assert.Throws(action); + } + } +} diff --git a/src/Core/Abstractions.Tests/ErrorTests.cs b/src/Core/Abstractions.Tests/ErrorTests.cs new file mode 100644 index 00000000000..2165220cafc --- /dev/null +++ b/src/Core/Abstractions.Tests/ErrorTests.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace HotChocolate +{ + public class ErrorTests + { + [Fact] + public void WithCode() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.WithCode("foo"); + + // assert + Assert.Equal("foo", error.Code); + } + + [Fact] + public void WithException() + { + // arrange + IError error = new Error { Message = "123" }; + var exception = new Exception(); + + // act + error = error.WithException(exception); + + // assert + Assert.Equal(exception, error.Exception); + } + + [Fact] + public void WithExtensions() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.WithExtensions( + new Dictionary { { "a", "b" } }); + + // assert + Assert.Collection(error.Extensions, + t => + { + Assert.Equal("a", t.Key); + Assert.Equal("b", t.Value); + }); + } + + [Fact] + public void AddExtensions() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.AddExtension("a", "b").AddExtension("c", "d"); + + // assert + Assert.Collection(error.Extensions.OrderBy(t => t.Key), + t => + { + Assert.Equal("a", t.Key); + Assert.Equal("b", t.Value); + }, + t => + { + Assert.Equal("c", t.Key); + Assert.Equal("d", t.Value); + }); + } + + [Fact] + public void RemoveExtensions() + { + // arrange + IError error = new Error { Message = "123" }; + error = error.WithExtensions( + new Dictionary + { + { "a", "b" }, + { "c", "d" } + }); + + // act + error = error.RemoveExtension("a"); + + // assert + Assert.Collection(error.Extensions, + t => + { + Assert.Equal("c", t.Key); + Assert.Equal("d", t.Value); + }); + } + + [Fact] + public void WithLocations() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.WithLocations( + new List { new Location(1, 2) }); + + // assert + Assert.Collection(error.Locations, + t => + { + Assert.Equal(1, t.Line); + Assert.Equal(2, t.Column); + }); + } + + [Fact] + public void WithMessage() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.WithMessage("456"); + + // assert + Assert.Equal("456", error.Message); + } + + [Fact] + public void WithMessage_MessageNull_ArgumentException() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + Action action = () => error.WithMessage(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void WithMessage_MessageEmpty_ArgumentException() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + Action action = () => error.WithMessage(string.Empty); + + // assert + Assert.Throws(action); + } + + [Fact] + public void WithPath() + { + // arrange + IError error = new Error { Message = "123" }; + + // act + error = error.WithPath(Path.New("foo")); + + // assert + Assert.Collection(error.Path, + t => Assert.Equal("foo", t.ToString())); + } + } +} diff --git a/src/Core/Abstractions/ErrorBuilder.cs b/src/Core/Abstractions/ErrorBuilder.cs index fd70a24aa82..14c5d7104eb 100644 --- a/src/Core/Abstractions/ErrorBuilder.cs +++ b/src/Core/Abstractions/ErrorBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; namespace HotChocolate { @@ -8,6 +9,32 @@ public class ErrorBuilder { private readonly Error _error = new Error(); + public ErrorBuilder() + { + } + + private ErrorBuilder(IError error) + { + if (error == null) + { + throw new ArgumentNullException(nameof(error)); + } + + _error.Message = error.Message; + _error.Code = error.Code; + _error.Exception = error.Exception; + if (error.Extensions != null && error.Extensions.Count > 0) + { + _error.Extensions = ImmutableDictionary + .CreateRange(error.Extensions); + } + if (error.Locations != null && error.Locations.Count > 0) + { + _error.Locations = ImmutableList.CreateRange(error.Locations); + } + _error.Path = error.Path; + } + public IErrorBuilder SetMessage(string message) { if (string.IsNullOrEmpty(message)) @@ -26,7 +53,7 @@ public IErrorBuilder SetCode(string code) return this; } - public IErrorBuilder SetPath(IReadOnlyCollection path) + public IErrorBuilder SetPath(IReadOnlyCollection path) { _error.Path = path; return this; @@ -87,5 +114,10 @@ public IError Build() } public static ErrorBuilder New() => new ErrorBuilder(); + + public static ErrorBuilder FromError(IError error) + { + return new ErrorBuilder(error); + } } } diff --git a/src/Core/Abstractions/IErrorBuilder.cs b/src/Core/Abstractions/IErrorBuilder.cs index 02f9a9d94fe..da90df6f54f 100644 --- a/src/Core/Abstractions/IErrorBuilder.cs +++ b/src/Core/Abstractions/IErrorBuilder.cs @@ -9,7 +9,7 @@ public interface IErrorBuilder IErrorBuilder SetCode(string code); - IErrorBuilder SetPath(IReadOnlyCollection path); + IErrorBuilder SetPath(IReadOnlyCollection path); IErrorBuilder SetPath(Path path); diff --git a/src/Core/Core.Tests/Execution/Middleware/QueryExecutionBuilderExtensionsTests.cs b/src/Core/Core.Tests/Execution/Middleware/QueryExecutionBuilderExtensionsTests.cs new file mode 100644 index 00000000000..04d8a5fad65 --- /dev/null +++ b/src/Core/Core.Tests/Execution/Middleware/QueryExecutionBuilderExtensionsTests.cs @@ -0,0 +1,357 @@ +using System; +using System.Threading.Tasks; +using HotChocolate.Execution.Configuration; +using HotChocolate.Resolvers; +using Xunit; + +namespace HotChocolate.Execution +{ + public class QueryExecutionBuilderExtensionsTests + { + [Fact] + public void UseDefaultPipeline1_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseDefaultPipeline(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseDefaultPipeline2_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseDefaultPipeline(null, new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseDefaultPipeline2_OptionsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseDefaultPipeline(QueryExecutionBuilder.New(), null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseExceptionHandling_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseExceptionHandling(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseInstrumentation_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseInstrumentation(null, default(TracingPreference)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseOperationExecutor_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseOperationExecutor(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseOperationResolver_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseOperationExecutor(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseQueryParser_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseOperationExecutor(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseRequestTimeout_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseRequestTimeout(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseValidation_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseValidation(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseMaxComplexity_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseMaxComplexity(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Use1_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .Use(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Use2_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .Use(null, (sp, next) => new object()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Use2_T_FactoryNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .Use(QueryExecutionBuilder.New(), null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseField1_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseField(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseField2_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseField(null, (sp, next) => new object()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void UseField2_T_FactoryNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .UseField(QueryExecutionBuilder.New(), null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + null, + new FieldReference("a", "b"), + next => context => Task.CompletedTask); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField_FieldReferenceNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + QueryExecutionBuilder.New(), + null, + next => context => Task.CompletedTask); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField_MiddlewareNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + QueryExecutionBuilder.New(), + new FieldReference("a", "b"), + null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField1_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + null, + new FieldReference("a", "b")); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField1_T_FieldReferenceNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + QueryExecutionBuilder.New(), + null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField2_T_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + null, + new FieldReference("a", "b"), + (sp, next) => new object()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField2_T_FieldReferenceNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + QueryExecutionBuilder.New(), + null, + (sp, next) => new object()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void MapField2_T_FactoryNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .MapField( + QueryExecutionBuilder.New(), + new FieldReference("a", "b"), + null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddExecutionStrategyResolver_BuilderNull_ArgNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .AddExecutionStrategyResolver(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddDefaultParser_BuilderNull_ArgumentNullException() + { + // arrange + // act + Action action = () => QueryExecutionBuilderExtensions + .AddDefaultParser(null); + + // assert + Assert.Throws(action); + } + } +} diff --git a/src/Core/Core/Execution/Middleware/QueryExecutionBuilderExtensions.cs b/src/Core/Core/Execution/Middleware/QueryExecutionBuilderExtensions.cs index 6f1d3771a4b..a74d3a2aa9e 100644 --- a/src/Core/Core/Execution/Middleware/QueryExecutionBuilderExtensions.cs +++ b/src/Core/Core/Execution/Middleware/QueryExecutionBuilderExtensions.cs @@ -228,7 +228,7 @@ public static IQueryExecutionBuilder UseField( FieldClassMiddlewareFactory.Create(factory)); } - public static IQueryExecutionBuilder Map( + public static IQueryExecutionBuilder MapField( this IQueryExecutionBuilder builder, FieldReference fieldReference, FieldMiddleware middleware) @@ -255,7 +255,7 @@ public static IQueryExecutionBuilder Map( } - public static IQueryExecutionBuilder Map( + public static IQueryExecutionBuilder MapField( this IQueryExecutionBuilder builder, FieldReference fieldReference) where TMiddleware : class @@ -282,7 +282,7 @@ public static IQueryExecutionBuilder Map( })); } - public static IQueryExecutionBuilder Map( + public static IQueryExecutionBuilder MapField( this IQueryExecutionBuilder builder, FieldReference fieldReference, Func factory) diff --git a/src/Core/Core/LegacyDataLoaderConfigurationExtensions.cs b/src/Core/Core/LegacyDataLoaderConfigurationExtensions.cs index cba13a37c11..5b4c8dc695e 100644 --- a/src/Core/Core/LegacyDataLoaderConfigurationExtensions.cs +++ b/src/Core/Core/LegacyDataLoaderConfigurationExtensions.cs @@ -8,7 +8,7 @@ public static class DataLoaderConfigurationExtensions { [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -25,7 +25,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -43,7 +43,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -59,7 +59,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -75,7 +75,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -90,7 +90,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -106,7 +106,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -122,7 +122,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -139,7 +139,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -154,7 +154,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -170,7 +170,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -185,7 +185,7 @@ public static void RegisterDataLoader( [Obsolete( "Use the DataLoaderRegistry instead. " + - "See https://hotchocolate.io/docs/migrate_dataloader " + + "See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] diff --git a/src/Core/Types.Tests/DataLoader/DataLoaderResolverContextExtensions.cs b/src/Core/Types.Tests/DataLoader/DataLoaderResolverContextExtensions.cs new file mode 100644 index 00000000000..0cb15606710 --- /dev/null +++ b/src/Core/Types.Tests/DataLoader/DataLoaderResolverContextExtensions.cs @@ -0,0 +1,431 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GreenDonut; +using HotChocolate.DataLoader; +using HotChocolate.Utilities; +using Moq; +using Xunit; + +namespace HotChocolate.Resolvers +{ + public class DataLoaderResolverContextExtensionsTests + { + [Fact] + public void BatchDataLoader_1_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + null, + "abc", + new FetchBatch(keys => Task + .FromResult>( + null))); + + // act + Assert.Throws(a); + } + + [Fact] + public void BatchDataLoader_1_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + resolverContext.Object, + null, + new FetchBatch(keys => Task + .FromResult>( + null))); + + // act + Assert.Throws(a); + } + + [Fact] + public void BatchDataLoader_1_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + resolverContext.Object, + "123", + default(FetchBatch)); + + // act + Assert.Throws(a); + } + + [Fact] + public void BatchDataLoader_2_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + null, + "abc", + new FetchBatchCt((keys, ct) => Task + .FromResult>( + null))); + + // act + Assert.Throws(a); + } + + [Fact] + public void BatchDataLoader_2_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + resolverContext.Object, + null, + new FetchBatchCt((keys, ct) => Task + .FromResult>( + null))); + + // act + Assert.Throws(a); + } + + [Fact] + public void BatchDataLoader_2_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .BatchDataLoader( + resolverContext.Object, + "123", + default(FetchBatchCt)); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_1_ContextNull_ArgNullException() + { + // arrange + var lookup = new Mock>(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + null, + "abc", + new FetchGroup(keys => + Task.FromResult(lookup.Object))); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_1_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + var lookup = new Mock>(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + resolverContext.Object, + null, + new FetchGroup(keys => + Task.FromResult(lookup.Object))); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_1_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + resolverContext.Object, + "123", + default(FetchGroup)); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_2_ContextNull_ArgNullException() + { + // arrange + var lookup = new Mock>(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + null, + "abc", + new FetchGroupCt((keys, ct) => + Task.FromResult(lookup.Object))); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_2_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + var lookup = new Mock>(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + resolverContext.Object, + null, + new FetchGroupCt((keys, ct) => + Task.FromResult(lookup.Object))); + + // act + Assert.Throws(a); + } + + [Fact] + public void GroupDataLoader_2_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .GroupDataLoader( + resolverContext.Object, + "123", + default(FetchGroupCt)); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_1_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + null, + "abc", + new FetchCache(keys => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_1_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + resolverContext.Object, + null, + new FetchCache(keys => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_1_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + resolverContext.Object, + "123", + default(FetchCache)); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_2_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + null, + "abc", + new FetchCacheCt((keys, ct) => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_2_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + resolverContext.Object, + null, + new FetchCacheCt((keys, ct) => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void CacheDataLoader_2_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .CacheDataLoader( + resolverContext.Object, + "123", + default(FetchCacheCt)); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_1_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + null, + "abc", + new FetchOnce(() => Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_1_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + resolverContext.Object, + null, + new FetchOnce(() => Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_1_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + resolverContext.Object, + "123", + default(FetchOnce)); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_2_ContextNull_ArgNullException() + { + // arrange + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + null, + "abc", + new FetchOnceCt(ct => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_2_KeyNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + resolverContext.Object, + null, + new FetchOnceCt(ct => + Task.FromResult(string.Empty))); + + // act + Assert.Throws(a); + } + + [Fact] + public void FetchOnceAsync_2_FetchNull_ArgNullException() + { + // arrange + var resolverContext = new Mock(); + + // assert + Action a = () => DataLoaderResolverContextExtensions + .FetchOnceAsync( + resolverContext.Object, + "123", + default(FetchOnceCt)); + + // act + Assert.Throws(a); + } + } +} diff --git a/src/Core/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs b/src/Core/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs index acd54c89708..6db12b6b6e1 100644 --- a/src/Core/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs +++ b/src/Core/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs @@ -7,6 +7,17 @@ namespace HotChocolate.Types { public class ArgumentDescriptorTests { + [Fact] + public void Create_TypeIsNull_ArgumentNullException() + { + // arrange + // act + Action action = () => new ArgumentDescriptor("Type", null); + + // assert + Assert.Throws(action); + } + [Fact] public void DotNetTypesDoNotOverwriteSchemaTypes() { @@ -24,6 +35,21 @@ public void DotNetTypesDoNotOverwriteSchemaTypes() Assert.Equal(typeof(ListType), typeRef.ClrType); } + [Fact] + public void SetTypeInstance() + { + // arrange + var descriptor = new ArgumentDescriptor("Type"); + + // act + ((IArgumentDescriptor)descriptor).Type(new StringType()); + + // assert + ArgumentDescription description = descriptor.CreateDescription(); + TypeReference typeRef = description.TypeReference; + Assert.IsType(typeRef.SchemaType); + } + [Fact] public void SchemaTypesOverwriteDotNetTypes() { @@ -96,6 +122,21 @@ public void SetDefaultValueAndInferType() description.NativeDefaultValue); } + [Fact] + public void SetDefaultValueNull() + { + // arrange + var descriptor = new ArgumentDescriptor("args"); + + // act + ((IArgumentDescriptor)descriptor).DefaultValue(null); + + // assert + ArgumentDescription description = descriptor.CreateDescription(); + Assert.Equal(NullValueNode.Default, description.DefaultValue); + Assert.Null(description.NativeDefaultValue); + } + [Fact] public void OverwriteDefaultValueLiteralWithNativeDefaultValue() { diff --git a/src/Core/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs b/src/Core/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs index 7b2a07f578e..62e8396340b 100644 --- a/src/Core/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs +++ b/src/Core/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs @@ -43,6 +43,23 @@ public void SchemaTypesOverwriteDotNetTypes() Assert.Equal(typeof(ListType), typeRef.ClrType); } + [Fact] + public void SetSchemaType() + { + // arrange + var descriptor = new InputFieldDescriptor( + typeof(ObjectField).GetProperty("Arguments")); + + // act + ((IInputFieldDescriptor)descriptor) + .Type(new StringType()); + + // assert + InputFieldDescription description = descriptor.CreateDescription(); + TypeReference typeRef = description.TypeReference; + Assert.IsType(typeRef.SchemaType); + } + [Fact] public void OverwriteName() { diff --git a/src/Core/Types.Tests/Types/Descriptors/ResolverObjectFieldDescriptorExtensionsTests.cs b/src/Core/Types.Tests/Types/Descriptors/ResolverObjectFieldDescriptorExtensionsTests.cs new file mode 100644 index 00000000000..0b7f40bad70 --- /dev/null +++ b/src/Core/Types.Tests/Types/Descriptors/ResolverObjectFieldDescriptorExtensionsTests.cs @@ -0,0 +1,461 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using HotChocolate.Resolvers; +using Moq; +using Xunit; + +namespace HotChocolate.Types +{ + public class ResolverObjectFieldDescriptorExtensionsTests + { + [Fact] + public void Resolver_IResolverContextObject_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func(c => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextObject_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public async Task Resolver_IResolverContextObject_ResolverIsSet() + { + // arrange + FieldResolverDelegate resolver = null; + var resolverFunc = new Func(c => "foo"); + var descriptor = new Mock(); + descriptor.Setup(t => t.Resolver(It.IsAny())) + .Returns( + new Func( + r => + { + resolver = r; + return descriptor.Object; + })); + + // act + ResolverObjectFieldDescriptorExtensions + .Resolver(descriptor.Object, resolverFunc); + + // assert + Assert.Equal("foo", await resolver.Invoke( + new Mock().Object)); + } + + [Fact] + public void Resolver_IResolverContextTaskOfObject_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>(c => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextTaskOfObject_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func(c => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextT_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextTaskOfT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>(c => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextTaskOfT_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_Object_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func(() => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_Object_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_TaskOfObject_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>(() => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_TaskOfObject_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_T_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func(() => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_T_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_TaskOfT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>(() => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_TaskOfT_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtObject_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func( + (c, ct) => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtObject_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default( + Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtTaskOfObject_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>((c, ct) => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverCtxCtTaskOfObject_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func( + (c, ct) => new object())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtT_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default( + Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverContextCtTaskOfT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + null, + new Func>((c, ct) => + Task.FromResult(new object()))); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_IResolverCtxCtTaskOfT_ResolverNull_ArgExc() + { + // arrange + var descriptor = new Mock(); + + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver( + descriptor.Object, + default(Func>)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_Constant_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver(null, new object()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Resolver_ConstantT_DescNull_ArgExc() + { + // arrange + // act + Action action = () => + ResolverObjectFieldDescriptorExtensions + .Resolver(null, new object()); + + // assert + Assert.Throws(action); + } + } +} diff --git a/src/Core/Types.Tests/Types/ListTypeTests.cs b/src/Core/Types.Tests/Types/ListTypeTests.cs index 1f602136e2e..61fe7f92f43 100644 --- a/src/Core/Types.Tests/Types/ListTypeTests.cs +++ b/src/Core/Types.Tests/Types/ListTypeTests.cs @@ -7,6 +7,53 @@ namespace HotChocolate.Types { public class ListTypeTests { + [Fact] + public void Create_ElementTypeNull_ArgNullExec() + { + // arrange + // act + Action action = () => new ListType(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void Create_ElementTypeIsListType_ArgExec() + { + // arrange + // act + Action action = () => new ListType(new ListType(new StringType())); + + // assert + Assert.Throws(action); + } + + [Fact] + public void InstanceOf_LiteralIsNull_ArgNullExec() + { + // arrange + // act + Action action = () => new ListType(new StringType()) + .IsInstanceOfType(null); + + // assert + Assert.Throws(action); + } + + [Fact] + public void InstanceOf_ElementTypeIsOutType_InvalidExec() + { + // arrange + // act + Action action = () => new ListType( + new ObjectType(c => c.Name("foo"))) + .IsInstanceOfType(new StringValueNode("foo")); + + // assert + Assert.Throws(action); + } + [Fact] public void EnsureElementTypeIsCorrectlySet() { diff --git a/src/Core/Types/Configuration/ICustomContextConfiguration.cs b/src/Core/Types/Configuration/ICustomContextConfiguration.cs index fbac121e997..4f0ce9e361b 100644 --- a/src/Core/Types/Configuration/ICustomContextConfiguration.cs +++ b/src/Core/Types/Configuration/ICustomContextConfiguration.cs @@ -8,7 +8,7 @@ public interface ICustomContextConfiguration { [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] diff --git a/src/Core/Types/Configuration/IDataLoaderConfiguration.cs b/src/Core/Types/Configuration/IDataLoaderConfiguration.cs index a2c251f4ebb..6c20afcef3c 100644 --- a/src/Core/Types/Configuration/IDataLoaderConfiguration.cs +++ b/src/Core/Types/Configuration/IDataLoaderConfiguration.cs @@ -10,7 +10,7 @@ public interface IDataLoaderConfiguration { [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -22,7 +22,7 @@ void RegisterDataLoader(Type type, [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] diff --git a/src/Core/Types/Configuration/SchemaConfiguration.CustomContext.cs b/src/Core/Types/Configuration/SchemaConfiguration.CustomContext.cs index a2780f0468f..695f9e70f81 100644 --- a/src/Core/Types/Configuration/SchemaConfiguration.CustomContext.cs +++ b/src/Core/Types/Configuration/SchemaConfiguration.CustomContext.cs @@ -7,7 +7,7 @@ internal partial class SchemaConfiguration { [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] diff --git a/src/Core/Types/Configuration/SchemaConfiguration.DataLoader.cs b/src/Core/Types/Configuration/SchemaConfiguration.DataLoader.cs index b7576724b00..0a9556a5880 100644 --- a/src/Core/Types/Configuration/SchemaConfiguration.DataLoader.cs +++ b/src/Core/Types/Configuration/SchemaConfiguration.DataLoader.cs @@ -9,7 +9,7 @@ internal partial class SchemaConfiguration { [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] @@ -24,7 +24,7 @@ public void RegisterDataLoader(Type type, [Obsolete( "Use the IQueryContext.ContextData / IResolverContext.ContextData" + - "instead. See https://hotchocolate.io/docs/migrate_dataloader " + + "instead. See https://hotchocolate.io/docs/migration " + "for more information." + "This type will be removed with version 1.0.0.", true)] diff --git a/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs b/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs index 2b3d9eaf175..62460c3d996 100644 --- a/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs +++ b/src/Core/Types/DataLoader/DataLoaderRegistryExtensions.cs @@ -77,7 +77,7 @@ public static bool Register( public static bool Register( this IDataLoaderRegistry registry, string key, - FetchGroupe fetch) + FetchGroup fetch) { if (string.IsNullOrEmpty(key)) { diff --git a/src/Core/Types/DataLoader/DataLoaderResolverContextExtensions.cs b/src/Core/Types/DataLoader/DataLoaderResolverContextExtensions.cs index 8c6158fbb6c..4e39c08103a 100644 --- a/src/Core/Types/DataLoader/DataLoaderResolverContextExtensions.cs +++ b/src/Core/Types/DataLoader/DataLoaderResolverContextExtensions.cs @@ -102,7 +102,7 @@ public static IDataLoader GroupDataLoader( this IResolverContext context, string key, - FetchGroupe fetch) + FetchGroup fetch) { if (context == null) { @@ -129,7 +129,7 @@ public static IDataLoader GroupDataLoader( this IResolverContext context, string key, - FetchGroupeCt fetch) + FetchGroupCt fetch) { if (context == null) { diff --git a/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs b/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs index 9f638b741a6..b1d34b72833 100644 --- a/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs +++ b/src/Core/Types/DataLoader/FetchGroupedDataLoader.cs @@ -10,9 +10,9 @@ namespace HotChocolate.DataLoader internal sealed class FetchGroupedDataLoader : DataLoaderBase { - private readonly FetchGroupe _fetch; + private readonly FetchGroup _fetch; - public FetchGroupedDataLoader(FetchGroupe fetch) + public FetchGroupedDataLoader(FetchGroup fetch) : base(new DataLoaderOptions { AutoDispatching = false, diff --git a/src/Core/Types/DataLoader/IDataLoaderRegistry.cs b/src/Core/Types/DataLoader/IDataLoaderRegistry.cs index b7ff936f2d4..8d8db3b8da0 100644 --- a/src/Core/Types/DataLoader/IDataLoaderRegistry.cs +++ b/src/Core/Types/DataLoader/IDataLoaderRegistry.cs @@ -18,13 +18,13 @@ public delegate Task> IReadOnlyList keys, CancellationToken cancellationToken); - public delegate FetchGroupe FetchGroupeFactory( + public delegate FetchGroup FetchGroupeFactory( IServiceProvider services); - public delegate Task> FetchGroupe( + public delegate Task> FetchGroup( IReadOnlyList keys); - public delegate Task> FetchGroupeCt( + public delegate Task> FetchGroupCt( IReadOnlyList keys, CancellationToken cancellationToken); diff --git a/src/Core/Utilities.Tests/ActivatorHelperTests.cs b/src/Core/Utilities.Tests/ActivatorHelperTests.cs new file mode 100644 index 00000000000..94d21ef8717 --- /dev/null +++ b/src/Core/Utilities.Tests/ActivatorHelperTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Reflection; +using Xunit; + +namespace HotChocolate.Utilities +{ + public class ActivatorHelperTests + { + [Fact] + public void CreateInstanceFactory_TypeInfoNull_ArgExec() + { + // arrange + // act + Action action = () => ActivatorHelper + .CreateInstanceFactory(default(TypeInfo)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void CreateInstanceFactoryT_TypeInfoNull_ArgExec() + { + // arrange + // act + Action action = () => ActivatorHelper + .CreateInstanceFactory(default(TypeInfo)); + + // assert + Assert.Throws(action); + } + } +} diff --git a/src/Core/Utilities/ActivatorHelper.cs b/src/Core/Utilities/ActivatorHelper.cs index 8402568be09..2589940a204 100644 --- a/src/Core/Utilities/ActivatorHelper.cs +++ b/src/Core/Utilities/ActivatorHelper.cs @@ -85,6 +85,4 @@ private static IEnumerable CreateParameters( } } } - - } diff --git a/src/Server/AspNetCore.Tests/ServiceCollectionExtensionsTests.cs b/src/Server/AspNetCore.Tests/ServiceCollectionExtensionsTests.cs new file mode 100644 index 00000000000..f5ae777adc2 --- /dev/null +++ b/src/Server/AspNetCore.Tests/ServiceCollectionExtensionsTests.cs @@ -0,0 +1,493 @@ +using System; +using HotChocolate.Execution; +using HotChocolate.Execution.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace HotChocolate.AspNetCore +{ + public class ServiceCollectionExtensionsTests + { + [Fact] + public void AddGraphQL_ServicesSchema_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, schema); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchema_SchemaNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), default(Schema)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactory_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, new Func(s => schema)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactory_SchemaFactoryNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryBuilder_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + new Func(s => schema), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryBuilder_SchemaFactoryNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Func), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryBuilder_BuilderNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + new Func(s => schema), + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesConfigure_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + new Action(c => { })); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesConfigure_ConfigureNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Action)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesConfigureBuilder_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + new Action(c => { }), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesConfigureBuilder_ConfigureNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Action), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesConfigureBuilder_BuilderNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + new Action(c => { }), + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigure_ServiceNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + "type Query { a: String }", + new Action(c => { })); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigure_SchemaSdlNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(string), + new Action(c => { })); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigure_SchemaSdlEmpty() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + string.Empty, + new Action(c => { })); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigure_ConfigureNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + "type Query { a: String }", + default(Action)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigureBld_ServiceNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + "type Query { a: String }", + new Action(c => { }), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigureBld_SchemaSdlNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(string), + new Action(c => { }), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigureBld_SchemaSdlEmpty() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + string.Empty, + new Action(c => { }), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigureBld_ConfigureNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + "type Query { a: String }", + default(Action), + new Func( + b => b)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaSdlConfigureBld_BuilderNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + "type Query { a: String }", + new Action(c => { }), + default(Func)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaOptions_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + schema, + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaOptions_SchemaNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Schema), + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaOptions_OptionsNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + schema, + default(IQueryExecutionOptionsAccessor)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryOptions_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + sp => schema, + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryOptions_SchemaNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Func), + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaFactoryOptions_OptionsNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + sp => schema, + default(IQueryExecutionOptionsAccessor)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaConfigOptions_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + new Action(c => { }), + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaConfigOptions_SchemaNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(Action), + new QueryExecutionOptions()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesSchemaConfigOptions_OptionsNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + new Action(c => { }), + default(IQueryExecutionOptionsAccessor)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesQueryExecutor_ServiceNull() + { + // arrange + var schema = Schema.Create(c => c.Options.StrictValidation = false); + + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + null, + schema.MakeExecutable()); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddGraphQL_ServicesQueryExecutor_ExecutorNull() + { + // arrange + // act + Action action = () => ServiceCollectionExtensions.AddGraphQL( + new ServiceCollection(), + default(IQueryExecutor)); + + // assert + Assert.Throws(action); + } + } +} diff --git a/src/Server/AspNetCore/ServiceCollectionExtensions.cs b/src/Server/AspNetCore/ServiceCollectionExtensions.cs index 3e9487d184a..7bce646621e 100644 --- a/src/Server/AspNetCore/ServiceCollectionExtensions.cs +++ b/src/Server/AspNetCore/ServiceCollectionExtensions.cs @@ -5,10 +5,6 @@ namespace HotChocolate { - public delegate IQueryExecutor BuildExecutor( - IServiceProvider services, - IQueryExecutionBuilder builder); - public static class ServiceCollectionExtensions { public static IServiceCollection AddGraphQL( @@ -371,28 +367,6 @@ public static IServiceCollection AddGraphQL( return serviceCollection .AddSingleton(executor) - .AddSingleton(s => - s.GetRequiredService().Schema) - .AddJsonSerializer(); - } - - public static IServiceCollection AddGraphQL( - this IServiceCollection serviceCollection, - BuildExecutor buildExecutor) - { - if (serviceCollection == null) - { - throw new ArgumentNullException(nameof(serviceCollection)); - } - - if (buildExecutor == null) - { - throw new ArgumentNullException(nameof(buildExecutor)); - } - - return serviceCollection - .AddSingleton(s => - buildExecutor(s, QueryExecutionBuilder.New())) .AddSingleton(s => s.GetRequiredService().Schema) .AddJsonSerializer(); diff --git a/src/Stitching/Stitching.Tests/DelegateToRemoteSchemaMiddlewareTests.cs b/src/Stitching/Stitching.Tests/DelegateToRemoteSchemaMiddlewareTests.cs index 0e4e56d4915..3ed4e9a465d 100644 --- a/src/Stitching/Stitching.Tests/DelegateToRemoteSchemaMiddlewareTests.cs +++ b/src/Stitching/Stitching.Tests/DelegateToRemoteSchemaMiddlewareTests.cs @@ -204,14 +204,16 @@ public async Task ExecuteStitchedQueryWithComputedField() serviceCollection.AddSingleton(httpClientFactory.Object); - serviceCollection.AddRemoteQueryExecutor(b => b - .SetSchemaName("contract") - .SetSchema(FileResource.Open("Contract.graphql")) - .AddScalarType()); - - serviceCollection.AddRemoteQueryExecutor(b => b - .SetSchemaName("customer") - .SetSchema(FileResource.Open("Customer.graphql"))); + serviceCollection.AddSingleton( + StitchingContextBuilder.New() + .AddExecutor(RemoteExecutorBuilder.New() + .SetSchemaName("Contract") + .SetSchema(FileResource.Open("Contract.graphql")) + .AddScalarType()) + .AddExecutor(RemoteExecutorBuilder.New() + .SetSchemaName("customer") + .SetSchema(FileResource.Open("Customer.graphql"))) + .Build()); serviceCollection.AddStitchedSchema( FileResource.Open("StitchingComputed.graphql"), diff --git a/src/Stitching/Stitching.Tests/StitchingContextBuilderTests.cs b/src/Stitching/Stitching.Tests/StitchingContextBuilderTests.cs new file mode 100644 index 00000000000..5fd1724ef70 --- /dev/null +++ b/src/Stitching/Stitching.Tests/StitchingContextBuilderTests.cs @@ -0,0 +1,101 @@ +using System; +using ChilliCream.Testing; +using HotChocolate.Execution; +using HotChocolate.Types; +using Moq; +using Xunit; + +namespace HotChocolate.Stitching +{ + public class StitchingContextBuilderTests + { + [Fact] + public void CreateContext() + { + // arrange + // act + IStitchingContext context = StitchingContextBuilder.New() + .AddExecutor(RemoteExecutorBuilder.New() + .SetSchemaName("Contract") + .SetSchema(FileResource.Open("Contract.graphql")) + .AddScalarType()) + .AddExecutor(RemoteExecutorBuilder.New() + .SetSchemaName("customer") + .SetSchema(FileResource.Open("Customer.graphql"))) + .Build(); + + // assert + Assert.NotNull(context.GetRemoteQueryClient("Contract")); + Assert.Throws( + () => context.GetRemoteQueryClient("Foo")); + } + + [Fact] + public void Build_NoExecutors_InvalidOperationException() + { + // arrange + // act + Action action = () => StitchingContextBuilder.New().Build(); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddExecuter_1_RemoteExecutorBuilderNull_ArgNullException() + { + // arrange + // act + Action action = () => StitchingContextBuilder.New() + .AddExecutor(default(RemoteExecutorBuilder)); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddExecuter_2_SchemaNullNull_ArgumentException() + { + // arrange + var executor = new Mock(); + + // act + Action action = () => StitchingContextBuilder.New() + .AddExecutor(null, executor.Object); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddExecuter_2_ExecutorNull_ArgumentNullException() + { + // arrange + var executor = new Mock(); + + // act + Action action = () => StitchingContextBuilder.New() + .AddExecutor(null, executor.Object); + + // assert + Assert.Throws(action); + } + + [Fact] + public void AddExecuter_3_BuilderNull_ArgumentNullException() + { + // arrange + var executor = new Mock(); + + // act + Action action = () => StitchingContextBuilder.New() + .AddExecutor + ( + default(Func) + ); + + // assert + Assert.Throws(action); + } + } +}