-
-
Notifications
You must be signed in to change notification settings - Fork 749
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test cases for External Arguments Default Mismatch rule.
- Loading branch information
1 parent
664a518
commit ad5d476
Showing
3 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
85 changes: 85 additions & 0 deletions
85
...t/src/Fusion.Composition/PreMergeValidation/Rules/ExternalArgumentsDefaultMismatchRule.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using HotChocolate.Fusion.Events; | ||
using HotChocolate.Skimmed; | ||
using static HotChocolate.Fusion.Logging.LogEntryHelper; | ||
|
||
namespace HotChocolate.Fusion.PreMergeValidation.Rules; | ||
|
||
/// <summary> | ||
/// This rule ensures that certain essential elements of a GraphQL schema, particularly built-in | ||
/// scalars, directive arguments, and introspection types, cannot be marked as @inaccessible. These | ||
/// types are fundamental to GraphQL. Making these elements inaccessible would break core GraphQL | ||
/// functionality. | ||
/// </summary> | ||
/// <seealso href="https://graphql.github.io/composite-schemas-spec/draft/#sec-Disallowed-Inaccessible-Elements"> | ||
/// Specification | ||
/// </seealso> | ||
internal sealed class ExternalArgumentsDefaultMismatchRule | ||
: IEventHandler<TypeEvent> | ||
, IEventHandler<OutputFieldEvent> | ||
, IEventHandler<FieldArgumentEvent> | ||
, IEventHandler<DirectiveArgumentEvent> | ||
{ | ||
public void Handle(TypeEvent @event, CompositionContext context) | ||
{ | ||
var (type, schema) = @event; | ||
|
||
// Built-in scalar types must be accessible. | ||
if (type is ScalarTypeDefinition { IsSpecScalar: true } scalar | ||
&& !ValidationHelper.IsAccessible(scalar)) | ||
{ | ||
context.Log.Write(DisallowedInaccessibleBuiltInScalar(scalar, schema)); | ||
} | ||
|
||
// Introspection types must be accessible. | ||
if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(type)) | ||
{ | ||
context.Log.Write(DisallowedInaccessibleIntrospectionType(type, schema)); | ||
} | ||
} | ||
|
||
public void Handle(OutputFieldEvent @event, CompositionContext context) | ||
{ | ||
var (field, type, schema) = @event; | ||
|
||
// Introspection fields must be accessible. | ||
if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(field)) | ||
{ | ||
context.Log.Write( | ||
DisallowedInaccessibleIntrospectionField( | ||
field, | ||
type.Name, | ||
schema)); | ||
} | ||
} | ||
|
||
public void Handle(FieldArgumentEvent @event, CompositionContext context) | ||
{ | ||
var (argument, field, type, schema) = @event; | ||
|
||
// Introspection arguments must be accessible. | ||
if (type.IsIntrospectionType && !ValidationHelper.IsAccessible(argument)) | ||
{ | ||
context.Log.Write( | ||
DisallowedInaccessibleIntrospectionArgument( | ||
argument, | ||
field.Name, | ||
type.Name, | ||
schema)); | ||
} | ||
} | ||
|
||
public void Handle(DirectiveArgumentEvent @event, CompositionContext context) | ||
{ | ||
var (argument, directive, schema) = @event; | ||
|
||
// Built-in directive arguments must be accessible. | ||
if (BuiltIns.IsBuiltInDirective(directive.Name) && !ValidationHelper.IsAccessible(argument)) | ||
{ | ||
context.Log.Write( | ||
DisallowedInaccessibleDirectiveArgument( | ||
argument, | ||
directive.Name, | ||
schema)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
...n.Composition.Tests/PreMergeValidation/Rules/ExternalArgumentsDefaultMismatchRuleTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
using HotChocolate.Fusion; | ||
using HotChocolate.Fusion.Logging; | ||
using HotChocolate.Fusion.PreMergeValidation; | ||
using HotChocolate.Fusion.PreMergeValidation.Rules; | ||
using HotChocolate.Skimmed.Serialization; | ||
|
||
namespace HotChocolate.Composition.PreMergeValidation.Rules; | ||
|
||
public sealed class ExternalArgumentsDefaultMismatchRuleTests | ||
{ | ||
[Test] | ||
[MethodDataSource(nameof(ValidExamplesData))] | ||
public async Task Examples_Valid(string[] sdl) | ||
{ | ||
// arrange | ||
var log = new CompositionLog(); | ||
var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); | ||
var preMergeValidator = new PreMergeValidator([new ExternalArgumentsDefaultMismatchRule()]); | ||
|
||
// act | ||
var result = preMergeValidator.Validate(context); | ||
|
||
// assert | ||
await Assert.That(result.IsSuccess).IsTrue(); | ||
await Assert.That(log.IsEmpty).IsTrue(); | ||
} | ||
|
||
[Test] | ||
[MethodDataSource(nameof(InvalidExamplesData))] | ||
public async Task Examples_Invalid(string[] sdl) | ||
{ | ||
// arrange | ||
var log = new CompositionLog(); | ||
var context = new CompositionContext([.. sdl.Select(SchemaParser.Parse)], log); | ||
var preMergeValidator = new PreMergeValidator([new ExternalArgumentsDefaultMismatchRule()]); | ||
|
||
// act | ||
var result = preMergeValidator.Validate(context); | ||
|
||
// assert | ||
await Assert.That(result.IsFailure).IsTrue(); | ||
await Assert.That(log.Count()).IsEqualTo(1); | ||
await Assert.That(log.First().Code).IsEqualTo("EXTERNAL_ARGUMENT_DEFAULT_MISMATCH"); | ||
await Assert.That(log.First().Severity).IsEqualTo(LogSeverity.Error); | ||
} | ||
|
||
public static IEnumerable<Func<string[]>> ValidExamplesData() | ||
{ | ||
return | ||
[ | ||
// Fields with the same arguments are mergeable. | ||
() => | ||
[ | ||
""" | ||
type Product { | ||
name(language: String = "en"): String | ||
} | ||
""", | ||
""" | ||
type Product { | ||
name(language: String = "en"): String @external | ||
} | ||
""" | ||
], | ||
]; | ||
} | ||
|
||
public static IEnumerable<Func<string[]>> InvalidExamplesData() | ||
{ | ||
return | ||
[ | ||
// Fields are not mergeable if the default arguments do not match | ||
() => | ||
[ | ||
""" | ||
type Product { | ||
name(language: String = "en"): String | ||
} | ||
""", | ||
""" | ||
type Product { | ||
name(language: String = "de"): String @external | ||
} | ||
""" | ||
], | ||
() => | ||
[ | ||
""" | ||
type Product { | ||
name(language: String = "en"): String | ||
} | ||
""", | ||
""" | ||
type Product { | ||
name(language: String): String @external | ||
} | ||
""" | ||
] | ||
]; | ||
} | ||
} |