Skip to content

Commit

Permalink
Stitching Introspection Fixes (#671)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Mar 29, 2019
1 parent dff5c2b commit 71ec0ab
Show file tree
Hide file tree
Showing 27 changed files with 2,020 additions and 30 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

## [0.8.1] - 2019-03-29

### Added

- Added operation start/stop event.
- Added error filter support for schema stitching.

Expand All @@ -31,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Non-nullable types are now validated when query uses variables. [#651](https://github.com/ChilliCream/hotchocolate/issues/651)
- Variable handling im middleware does not convert the DateTime value anymore. [#664](https://github.com/ChilliCream/hotchocolate/issues/664)
- Directives are now correctly merged when declared in an extension file. [#665](https://github.com/ChilliCream/hotchocolate/issues/665)
- Subscription is now optional in the 2-phase introspection call [#668](https://github.com/ChilliCream/hotchocolate/issues/668)

## [0.8.0] - 2019-03-03

Expand Down
48 changes: 46 additions & 2 deletions src/Core/Language.Tests/Lexer/LexerTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Xunit;
using System;
using Xunit;

namespace HotChocolate.Language
{
Expand Down Expand Up @@ -31,5 +32,48 @@ public void EnsureTokensAreDoublyLinked()
Assert.Equal(token.Next.Next, token.Next.Next.Next.Previous);
Assert.Null(token.Next.Next.Next.Next);
}

[Fact]
public void SourceIsNull_ArgumentNullException()
{
// arrange
Lexer lexer = new Lexer();

// act
Action action = () => lexer.Read(null);

// assert
Assert.Throws<ArgumentNullException>(action);
}

[Fact]
public void UnexpectedCharacter()
{
// arrange
Source source = new Source("~");
Lexer lexer = new Lexer();

// act
Action action = () => lexer.Read(source);

// assert
Assert.Equal("Unexpected character.",
Assert.Throws<SyntaxException>(action).Message);
}

[Fact]
public void UnexpectedTokenSequence()
{
// arrange
Source source = new Source("\"foo");
Lexer lexer = new Lexer();

// act
Action action = () => lexer.Read(source);

// assert
Assert.Equal("Unexpected token sequence.",
Assert.Throws<SyntaxException>(action).Message);
}
}
}
}
66 changes: 66 additions & 0 deletions src/Core/Language.Tests/Parser/ValueParserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using Xunit;

namespace HotChocolate.Language
{
public class ValueParserTests
{
[InlineData("true", true, typeof(BooleanValueNode))]
[InlineData("false", false, typeof(BooleanValueNode))]
[InlineData("0", "0", typeof(IntValueNode))]
[InlineData("123", "123", typeof(IntValueNode))]
[InlineData("-123", "-123", typeof(IntValueNode))]
[InlineData("2.3e-5", "2.3e-5", typeof(FloatValueNode))]
[InlineData("2.3e+5", "2.3e+5", typeof(FloatValueNode))]
[InlineData("123.456", "123.456", typeof(FloatValueNode))]
[InlineData("\"123\"", "123", typeof(StringValueNode))]
[InlineData("\"\"\"123\n456\"\"\"", "123\n456",
typeof(StringValueNode))]
[InlineData("\"\\u0031\"", "1", typeof(StringValueNode))]
[InlineData("\"\\u004E\"", "N", typeof(StringValueNode))]
[InlineData("\"\\u0061\"", "a", typeof(StringValueNode))]
[InlineData("\"\\u003A\"", ":", typeof(StringValueNode))]
[InlineData("FOO", "FOO", typeof(EnumValueNode))]
[Theory]
public void ParseSimpleValue(
string value,
object expectedValue,
Type expectedNodeType)
{
// arrange
// act
IValueNode valueNode = ParseValue(value);

// assert
Assert.Equal(expectedNodeType, valueNode.GetType());
Assert.Equal(expectedValue, valueNode.Value);
}

[Fact]
public void ZeroZeroIsNotAllowed()
{
// arrange
// act
Action action = () => ParseValue("00");

// assert
Assert.Throws<SyntaxException>(action);
}

private static IValueNode ParseValue(string value)
{
SyntaxToken start = Lexer.Default.Read(
new Source(value));

var context = new ParserContext(
new Source(value),
start,
ParserOptions.Default,
Parser.ParseName);
context.MoveNext();

return Parser.ParseValueLiteral(context, true);
}
}
}

2 changes: 2 additions & 0 deletions src/Core/Language/AST/BooleanValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public BooleanValueNode(

public bool Value { get; }

object IValueNode.Value => Value;

/// <summary>
/// Determines whether the specified <see cref="BooleanValueNode"/>
/// is equal to the current <see cref="BooleanValueNode"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/EnumValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public EnumValueNode(

public string Value { get; }

object IValueNode.Value => Value;

/// <summary>
/// Determines whether the specified <see cref="EnumValueNode"/>
/// is equal to the current <see cref="EnumValueNode"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/FloatValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public FloatValueNode(

public string Value { get; }

object IValueNode.Value => Value;

/// <summary>
/// Determines whether the specified <see cref="FloatValueNode"/>
/// is equal to the current <see cref="FloatValueNode"/>.
Expand Down
3 changes: 2 additions & 1 deletion src/Core/Language/AST/IValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ public interface IValueNode
: ISyntaxNode
, IEquatable<IValueNode>
{
object Value { get; }
}

public interface IValueNode<out T>
: IValueNode
{
T Value { get; }
new T Value { get; }
}
}
2 changes: 2 additions & 0 deletions src/Core/Language/AST/IntValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public IntValueNode(

public string Value { get; }

object IValueNode.Value => Value;

/// <summary>
/// Determines whether the specified <see cref="IntValueNode"/>
/// is equal to the current <see cref="IntValueNode"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/ListValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public ListValueNode(
IReadOnlyList<IValueNode> IValueNode<IReadOnlyList<IValueNode>>.Value =>
Items;

object IValueNode.Value => Items;

/// <summary>
/// Determines whether the specified <see cref="ListValueNode"/>
/// is equal to the current <see cref="ListValueNode"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/ObjectValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public ObjectValueNode(
IReadOnlyList<ObjectFieldNode>
IValueNode<IReadOnlyList<ObjectFieldNode>>.Value => Fields;

object IValueNode.Value => Fields;

/// <summary>
/// Determines whether the specified <see cref="ObjectValueNode"/>
/// is equal to the current <see cref="ObjectValueNode"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/StringValueNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public StringValueNode(

public string Value { get; }

object IValueNode.Value => Value;

/// <summary>
/// Gets a value indicating whether this <see cref="StringValueNode"/>
/// was parsed from a block string.
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Language/AST/VariableNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public VariableNode(

public string Value => Name.Value;

object IValueNode.Value => Value;

/// <summary>
/// Determines whether the specified <see cref="VariableNode"/>
/// is equal to the current <see cref="VariableNode"/>.
Expand Down
13 changes: 8 additions & 5 deletions src/Core/Language/Lexer/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public SyntaxToken Read(ISource source)

return start;
}
catch (Exception ex)
catch (Exception ex) when (!(ex is SyntaxException))
{
throw new SyntaxException(state,
"Unexpected token sequence.",
Expand Down Expand Up @@ -299,11 +299,14 @@ private static SyntaxToken ReadNumberToken(

if (code == '0')
{
code = state.SourceText[++state.Position];
if (char.IsDigit(code))
if (!state.IsEndOfStream(++state.Position))
{
throw new SyntaxException(state,
$"Invalid number, unexpected digit after 0: {code}.");
code = state.SourceText[state.Position];
if (char.IsDigit(code))
{
throw new SyntaxException(state,
$"Invalid number, unexpected digit after 0: {code}.");
}
}
}
else
Expand Down
10 changes: 10 additions & 0 deletions src/Core/Language/Lexer/LexerState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,15 @@ public bool IsEndOfStream()
{
return Position >= SourceText.Length;
}

/// <summary>
/// Checks if the lexer source pointer has reached
/// the end of the GraphQL source text.
/// </summary>
/// <returns></returns>
public bool IsEndOfStream(int position)
{
return position >= SourceText.Length;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using HotChocolate.Language;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Stitching.Introspection
{
public class IntrospectionClientTests
{
[Fact]
public void IntrospectionWithSubscription()
{
// arrange
var features = new SchemaFeatures
{
HasSubscriptionSupport = true
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void IntrospectionWithoutSubscription()
{
// arrange
var features = new SchemaFeatures
{
HasSubscriptionSupport = false
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void IntrospectionWithDirectiveLocationField()
{
// arrange
var features = new SchemaFeatures
{
HasDirectiveLocations = true
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void IntrospectionWithoutDirectiveLocationField()
{
// arrange
var features = new SchemaFeatures
{
HasDirectiveLocations = false
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void IntrospectionWithDirectiveIsRepeatableField()
{
// arrange
var features = new SchemaFeatures
{
HasRepeatableDirectives = true
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}

[Fact]
public void IntrospectionWithoutDirectiveIsRepeatableField()
{
// arrange
var features = new SchemaFeatures
{
HasRepeatableDirectives = false
};

// act
DocumentNode document =
IntrospectionClient.CreateIntrospectionQuery(features);

// assert
QuerySyntaxSerializer.Serialize(document).MatchSnapshot();
}
}
}
Loading

0 comments on commit 71ec0ab

Please sign in to comment.