Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented equality for ObjectTypeExtensionNode #4962

Merged
merged 4 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,51 @@
using System;
using System.Collections.Generic;
using HotChocolate.Language.Utilities;

namespace HotChocolate.Language;

/// <summary>
/// Object type extensions are used to represent a type which has been extended
/// from some original type. For example, this might be used to represent local data,
/// or by a GraphQL service which is itself an extension of another GraphQL service.
/// </summary>
public sealed class ObjectTypeExtensionNode
: ComplexTypeDefinitionNodeBase
, ITypeExtensionNode
, IEquatable<ObjectTypeExtensionNode>
{
/// <summary>
/// Initializes a new instance of <see cref="ObjectTypeExtensionNode"/>.
/// </summary>
/// <param name="location">
/// The location of the syntax node within the original source text.
/// </param>
/// <param name="name">
/// The name that this syntax node holds.
/// </param>
/// <param name="directives">
/// The directives that are annotated to this syntax node.
/// </param>
/// <param name="interfaces">
/// The interfaces that this type implements.
/// </param>
/// <param name="fields">
/// The fields that this type exposes.
/// </param>
public ObjectTypeExtensionNode(
Location? location,
NameNode name,
IReadOnlyList<DirectiveNode> directives,
IReadOnlyList<NamedTypeNode> interfaces,
IReadOnlyList<FieldDefinitionNode> fields)
: base(location, name, directives, interfaces, fields)
{ }
{
}

/// <inheritdoc />
public override SyntaxKind Kind => SyntaxKind.ObjectTypeExtension;

/// <inheritdoc />
public override IEnumerable<ISyntaxNode> GetNodes()
{
yield return Name;
Expand Down Expand Up @@ -59,41 +87,102 @@ public override IEnumerable<ISyntaxNode> GetNodes()
/// </returns>
public override string ToString(bool indented) => SyntaxPrinter.Print(this, indented);

/// <summary>
/// Creates a new node from the current instance and replaces the
/// <see cref="Location"/> with <paramref name="location"/>.
/// </summary>
/// <param name="location">
/// The location that shall be used to replace the current location.
/// </param>
/// <returns>
/// Returns the new node with the new <paramref name="location"/>
/// </returns>
public ObjectTypeExtensionNode WithLocation(Location? location)
{
return new ObjectTypeExtensionNode(
location, Name, Directives,
Interfaces, Fields);
}
=> new(location, Name, Directives, Interfaces, Fields);

/// <summary>
/// Creates a new node from the current instance and replaces the
/// <see cref="NameNode"/> with <paramref name="name"/>
/// </summary>
/// <param name="name">
/// The name that shall be used to replace the current name.
/// </param>
/// <returns>
/// Returns the new node with the new <paramref name="name"/>
/// </returns>
public ObjectTypeExtensionNode WithName(NameNode name)
{
return new ObjectTypeExtensionNode(
Location, name, Directives,
Interfaces, Fields);
}
=> new(Location, name, Directives, Interfaces, Fields);

public ObjectTypeExtensionNode WithDirectives(
IReadOnlyList<DirectiveNode> directives)
{
return new ObjectTypeExtensionNode(
Location, Name, directives,
Interfaces, Fields);
}
/// <summary>
/// Creates a new node from the current instance and replaces the
/// <see cref="NamedSyntaxNode.Directives"/> with <paramref name="directives"/>
/// </summary>
/// <param name="directives">
/// The directives that shall be used to replace the current directives.
/// </param>
/// <returns>
/// Returns the new node with the new <paramref name="directives"/>
/// </returns>
public ObjectTypeExtensionNode WithDirectives(IReadOnlyList<DirectiveNode> directives)
=> new(Location, Name, directives, Interfaces, Fields);

public ObjectTypeExtensionNode WithInterfaces(
IReadOnlyList<NamedTypeNode> interfaces)
{
return new ObjectTypeExtensionNode(
Location, Name, Directives,
interfaces, Fields);
}
/// <summary>
/// Creates a new node from the current instance and replaces the
/// <see cref="ComplexTypeDefinitionNodeBase.Interfaces"/> with <paramref name="interfaces"/>
/// </summary>
/// <param name="interfaces">
/// The interfaces that shall be used to replace the current interfaces.
/// </param>
/// <returns>
/// Returns the new node with the new <paramref name="interfaces"/>
/// </returns>
public ObjectTypeExtensionNode WithInterfaces(IReadOnlyList<NamedTypeNode> interfaces)
=> new(Location, Name, Directives, interfaces, Fields);

public ObjectTypeExtensionNode WithFields(
IReadOnlyList<FieldDefinitionNode> fields)
{
return new ObjectTypeExtensionNode(
Location, Name, Directives,
Interfaces, fields);
}
/// <summary>
/// Creates a new node from the current instance and replaces the
/// <see cref="ComplexTypeDefinitionNodeBase.Fields"/> with <paramref name="fields"/>
/// </summary>
/// <param name="fields">
/// The fields that shall be used to replace the current fields.
/// </param>
/// <returns>
/// Returns the new node with the new <paramref name="fields"/>
/// </returns>
public ObjectTypeExtensionNode WithFields(IReadOnlyList<FieldDefinitionNode> fields)
=> new(Location, Name, Directives, Interfaces, fields);

/// <inheritdoc />
public bool Equals(ObjectTypeExtensionNode? other) => base.Equals(other);

/// <inheritdoc />
public override bool Equals(object? obj)
=> ReferenceEquals(this, obj) ||
(obj is ObjectTypeExtensionNode other && Equals(other));

/// <inheritdoc />
public override int GetHashCode()
=> HashCode.Combine(base.GetHashCode(), Kind);

/// <summary>
/// The equal operator.
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>
/// <c>true</c> if <paramref name="left"/> and <paramref name="right"/> are equal.
/// </returns>
public static bool operator ==(ObjectTypeExtensionNode? left, ObjectTypeExtensionNode? right)
=> Equals(left, right);

/// <summary>
/// The not equal operator.
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>
/// <c>true</c> if <paramref name="left"/> and <paramref name="right"/> are not equal.
/// </returns>
public static bool operator !=(ObjectTypeExtensionNode? left, ObjectTypeExtensionNode? right)
=> !Equals(left, right);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private void VisitObjectTypeExtension(ObjectTypeExtensionNode node, ISyntaxWrite
}

private void VisitObjectTypeDefinitionBase(
ObjectTypeDefinitionNodeBase node,
ComplexTypeDefinitionNodeBase node,
ISyntaxWriter writer)
{
writer.Write(Keywords.Type);
Expand All @@ -60,9 +60,7 @@ private void VisitObjectTypeDefinitionBase(
writer.WriteSpace();
writer.Write(Keywords.Implements);
writer.WriteSpace();
writer.WriteMany(node.Interfaces,
(n, w) => writer.WriteNamedType(n),
" & ");
writer.WriteMany(node.Interfaces, (n, _) => writer.WriteNamedType(n), " & ");
}

WriteDirectives(node.Directives, writer);
Expand Down Expand Up @@ -159,9 +157,7 @@ private void VisitUnionTypeDefinitionBase(
writer.Write('=');
writer.WriteSpace();

writer.WriteMany(node.Types,
(n, w) => writer.WriteNamedType(n),
" | ");
writer.WriteMany(node.Types, (n, _) => writer.WriteNamedType(n), " | ");
}

private void VisitEnumTypeDefinition(
Expand Down Expand Up @@ -376,9 +372,7 @@ private void VisitDirectiveDefinition(
writer.Write(Keywords.On);
writer.WriteSpace();

writer.WriteMany(node.Locations,
(n, w) => writer.WriteName(n),
" | ");
writer.WriteMany(node.Locations, (n, _) => writer.WriteName(n), " | ");
}

private void VisitArgumentValueDefinition(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ public void GetHashCode_With_Location()
new StringValueNode("cc"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0)
);
new List<FieldDefinitionNode>(0));

// act
var aHash = a.GetHashCode();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System.Collections.Generic;
using Xunit;

namespace HotChocolate.Language.SyntaxTree;

public class ObjectTypeExtensionNodeTests
{
[Fact]
public void Equals_With_Same_Location()
{
// arrange
var a = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var b = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("bb"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var c = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));

// act
var aaResult = a.Equals(a);
var abResult = a.Equals(b);
var acResult = a.Equals(c);
var aNullResult = a.Equals(default);

// assert
Assert.True(aaResult);
Assert.False(abResult);
Assert.True(acResult);
Assert.False(aNullResult);
}

[Fact]
public void Equals_With_Different_Location()
{
// arrange
var a = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var b = new ObjectTypeExtensionNode(
TestLocations.Location2,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var c = new ObjectTypeExtensionNode(
TestLocations.Location3,
new NameNode("bb"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));

// act
var aaResult = a.Equals(a);
var abResult = a.Equals(b);
var acResult = a.Equals(c);

// assert
Assert.True(aaResult);
Assert.True(abResult);
Assert.False(acResult);
}

[Fact]
public void GetHashCode_With_Location()
{
// arrange
var a = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var b = new ObjectTypeExtensionNode(
TestLocations.Location2,
new NameNode("aa"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var c = new ObjectTypeExtensionNode(
TestLocations.Location1,
new NameNode("bb"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));
var d = new ObjectTypeExtensionNode(
TestLocations.Location2,
new NameNode("bb"),
new List<DirectiveNode>(0),
new List<NamedTypeNode>(0),
new List<FieldDefinitionNode>(0));

// act
var aHash = a.GetHashCode();
var bHash = b.GetHashCode();
var cHash = c.GetHashCode();
var dHash = d.GetHashCode();

// assert
Assert.Equal(aHash, bHash);
Assert.NotEqual(aHash, cHash);
Assert.Equal(cHash, dHash);
Assert.NotEqual(aHash, dHash);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ public void CompareGetHashCode_WithLocations()
// assert
Assert.Equal(aHash, bHash);
Assert.NotEqual(aHash, cHash);
Assert.Equal(cHash, dHash);
Assert.NotEqual(cHash, dHash);
}
}