Skip to content

Commit

Permalink
Support nodes field for automatic mocking (#7728)
Browse files Browse the repository at this point in the history
  • Loading branch information
tobias-tengler authored and michaelstaib committed Nov 19, 2024
1 parent 29bf673 commit 7934dfb
Show file tree
Hide file tree
Showing 22 changed files with 594 additions and 67 deletions.
531 changes: 525 additions & 6 deletions src/HotChocolate/Fusion/test/Core.Tests/AutomaticMockingTests.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
},
"other": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
},
"other": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string",
"other": "string"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": "string",
"other": "string"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"other": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"product": {
"id": "1",
"brand": {
"id": "1",
"id": "2",
"name": null
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using HotChocolate.Utilities;
Expand All @@ -9,10 +10,15 @@ internal sealed class MockFieldMiddleware
{
private const int DefaultListSize = 3;

private int _idCounter;

public ValueTask InvokeAsync(IMiddlewareContext context)
{
var mockingContext = context.GetGlobalStateOrDefault<AutomaticMockingContext>(nameof(AutomaticMockingContext));
if (mockingContext is null)
{
mockingContext = new AutomaticMockingContext();
context.SetGlobalState(nameof(AutomaticMockingContext), mockingContext);
}

var field = context.Selection.Field;
var fieldName = field.Name;
var fieldType = field.Type;
Expand Down Expand Up @@ -69,13 +75,16 @@ public ValueTask InvokeAsync(IMiddlewareContext context)
}
}

if (fieldName.EndsWith("ById"))
if (fieldName.EndsWith("ById") || fieldName is "node" or "nodes")
{
if (context.Selection.Arguments.ContainsName("id"))
{
var id = context.ArgumentValue<object>("id");
if (namedFieldType.IsObjectType())
if (namedFieldType.IsCompositeType())
{
var possibleTypes = context.Schema.GetPossibleTypes(namedFieldType);

context.ValueType = possibleTypes.First();
context.Result = CreateObject(id);
return ValueTask.CompletedTask;
}
Expand All @@ -91,10 +100,16 @@ public ValueTask InvokeAsync(IMiddlewareContext context)
nullableType = fieldType.InnerType();
}

if (nullableType.IsListType() && namedFieldType.IsObjectType())
if (nullableType.IsListType())
{
context.Result = CreateListOfObjects(ids, nullIndex);
return ValueTask.CompletedTask;
if (namedFieldType.IsCompositeType())
{
var possibleTypes = context.Schema.GetPossibleTypes(namedFieldType);

context.ValueType = possibleTypes.First();
context.Result = CreateListOfObjects(ids, nullIndex);
return ValueTask.CompletedTask;
}
}
}
}
Expand All @@ -109,56 +124,53 @@ public ValueTask InvokeAsync(IMiddlewareContext context)
}
}

if (fieldType.IsObjectType())
{
context.Result = CreateObject();
}
else if (fieldType.IsInterfaceType() || fieldType.IsUnionType())
var hasIdFieldSelection = context.Select().IsSelected("id");

if (fieldType.IsCompositeType())
{
int? id = hasIdFieldSelection ? ++mockingContext.IdCounter : null;
var possibleTypes = context.Schema.GetPossibleTypes(namedFieldType);

context.ValueType = possibleTypes.First();
context.Result = CreateObject();
context.Result = CreateObject(id);
}
else if (fieldType.IsListType())
{
if (namedFieldType.IsObjectType())
{
context.Result = CreateListOfObjects(null, nullIndex);
}
else if (namedFieldType.IsInterfaceType() || namedFieldType.IsUnionType())
if (namedFieldType.IsCompositeType())
{
var ids = Enumerable.Range(0, DefaultListSize)
.Select(_ => (object?)(hasIdFieldSelection ? ++mockingContext.IdCounter : null)).ToArray();
var possibleTypes = context.Schema.GetPossibleTypes(namedFieldType);

context.ValueType = possibleTypes.First();
context.Result = CreateListOfObjects(null, nullIndex);
context.Result = CreateListOfObjects(ids, nullIndex);
}
else if(namedFieldType is EnumType enumType)
else if (namedFieldType is EnumType enumType)
{
context.Result = CreateListOfEnums(enumType, nullIndex);
}
else
{
context.Result = CreateListOfScalars(namedFieldType, nullIndex);
context.Result = CreateListOfScalars(namedFieldType, nullIndex, mockingContext);
}
}
else if(namedFieldType is EnumType enumType)
else if (namedFieldType is EnumType enumType)
{
context.Result = CreateEnumValue(enumType);
}
else
{
context.Result = CreateScalarValue(namedFieldType);
context.Result = CreateScalarValue(namedFieldType, mockingContext);
}

return ValueTask.CompletedTask;
}

private object? CreateScalarValue(INamedType scalarType)
private object? CreateScalarValue(INamedType scalarType, AutomaticMockingContext mockingContext)
{
return scalarType switch
{
IdType => ++_idCounter,
IdType => ++mockingContext.IdCounter,
StringType => "string",
IntType => 123,
FloatType => 123.456,
Expand All @@ -172,17 +184,15 @@ public ValueTask InvokeAsync(IMiddlewareContext context)
return enumType.Values.FirstOrDefault()?.Value;
}

private object CreateObject(object? id = null, int? index = null)
private object CreateObject(object? id, int? index = null)
{
var finalId = id ?? ++_idCounter;

return new ObjectTypeInst(finalId, index);
return new ObjectTypeInst(id, index);
}

private object?[] CreateListOfScalars(INamedType scalarType, int? nullIndex)
private object?[] CreateListOfScalars(INamedType scalarType, int? nullIndex, AutomaticMockingContext mockingContext)
{
return Enumerable.Range(0, DefaultListSize)
.Select(index => nullIndex == index ? null : CreateScalarValue(scalarType))
.Select(index => nullIndex == index ? null : CreateScalarValue(scalarType, mockingContext))
.ToArray();
}

Expand All @@ -193,17 +203,10 @@ private object CreateObject(object? id = null, int? index = null)
.ToArray();
}

private object?[] CreateListOfObjects(object[]? ids, int? nullIndex)
private object?[] CreateListOfObjects(object?[] ids, int? nullIndex)
{
if (ids is not null)
{
return ids
.Select((itemId, index) => nullIndex == index ? null : CreateObject(itemId, index))
.ToArray();
}

return Enumerable.Range(0, DefaultListSize)
.Select(index => nullIndex == index ? null : CreateObject(null, index))
return ids
.Select((itemId, index) => nullIndex == index ? null : CreateObject(itemId, index))
.ToArray();
}

Expand All @@ -224,4 +227,9 @@ private static IError CreateError(IResolverContext context, int? index = null)
}

private record ObjectTypeInst(object? Id = null, int? Index = null);

private class AutomaticMockingContext
{
public int IdCounter { get; set; }
}
}

0 comments on commit 7934dfb

Please sign in to comment.