Skip to content

Commit

Permalink
Improve code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Struan Judd committed Jan 3, 2024
1 parent 49f80d7 commit 2c370d0
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 11 deletions.
4 changes: 3 additions & 1 deletion src/GqlPlus.Verifier/Parse/Schema/ParseNull.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using GqlPlus.Verifier.Ast;
using System.Diagnostics.CodeAnalysis;
using GqlPlus.Verifier.Ast;
using GqlPlus.Verifier.Result;
using GqlPlus.Verifier.Token;

namespace GqlPlus.Verifier.Parse.Schema;

internal class ParseNull : Parser<NullAst>.I
{
[ExcludeFromCodeCoverage]
public IResult<NullAst> Parse<TContext>(TContext tokens, string label)
where TContext : Tokenizer
=> 0.Empty<NullAst>();
Expand Down
6 changes: 3 additions & 3 deletions src/GqlPlus.Verifier/Parse/Schema/ParseScalar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ public IResult<ScalarDefinition> Parse<TContext>(TContext tokens, string label)
return tokens.End(label, () => result);
}

return scalarRegexes.AsResult(result); // not covered
return scalarRegexes.AsResult(result);
case ScalarKind.Union:
var scalarReferences = _references.Parse(tokens, label);
if (scalarReferences.Required(references => result.References = references)) {
return tokens.End(label, () => result);
}

return scalarReferences.AsResult(result); // not covered
return scalarReferences.AsResult(result);
default:
return tokens.Partial(label, "valid kind", () => result); // not covered
return tokens.Partial(label, "valid kind", () => result);
}
}
}
7 changes: 5 additions & 2 deletions src/GqlPlus.Verifier/Parse/Schema/ParseScalarRegex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ internal class ParseScalarRegex : Parser<ScalarRegexAst>.I
public IResult<ScalarRegexAst> Parse<TContext>(TContext tokens, string label)
where TContext : Tokenizer
{
ScalarRegexAst? result = null;
var at = tokens.At;
ScalarRegexAst? result;
if (tokens.Regex(out var regex)) {
var excluded = tokens.Take('!');
result = new(at, regex, excluded);
return result.Ok();
}

return result.Empty();
result = new(at, regex, false);
return string.IsNullOrEmpty(regex)
? result.Empty()
: tokens.Error(label, "Closing '/'", result);
}
}
2 changes: 1 addition & 1 deletion test/GqlPlus.Verifier.ClassTests/Ast/FieldKeyAstTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public class FieldKeyAstTests
{
[Fact]
public void HashCode_WithNull()
=> _checks.HashCode(() => new FieldKeyAst(AstNulls.At));
=> _checks.HashCode(() => new FieldKeyAst(AstNulls.At) with { At = AstNulls.At });

[Theory, RepeatData(Repeats)]
public void HashCode_WithNumber(decimal number)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using GqlPlus.Verifier.Ast;
using Newtonsoft.Json.Linq;

namespace GqlPlus.Verifier.Merging;

Expand Down
92 changes: 92 additions & 0 deletions test/GqlPlus.Verifier.ClassTests/Parse/ClassTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using GqlPlus.Verifier.Parse.Schema;
using GqlPlus.Verifier.Result;
using GqlPlus.Verifier.Token;
using NSubstitute;

namespace GqlPlus.Verifier.Parse;

public class ClassTestBase
{
protected static Tokenizer Tokens(string input)
{
var tokens = new Tokenizer(input);
tokens.Read();
return tokens;
}

internal static T NameFor<T>(string name)
where T : class, INameParser
{
var nameParser = Substitute.For<T>();
nameParser.ParseName(default!, out var _, out var _)
.ReturnsForAnyArgs(c => {
c[1] = name;
return true;
});
return nameParser;
}

protected static Parser<T>.D ParserFor<T>()
=> ParserFor<T>(out var _);

protected static Parser<T>.D ParserFor<T>(out Parser<T>.I parser)
{
parser = Substitute.For<Parser<T>.I>();
parser.Parse<Tokenizer>(default!, default!)
.ReturnsForAnyArgs(0.Empty<T>());

var result = Substitute.For<Parser<T>.D>();
result().Returns(parser);

return result;
}

protected static Parser<IOptionParser<T>, T>.D OptionParserFor<T>()
where T : struct
=> OptionParserFor<T>(out var _);

protected static Parser<IOptionParser<T>, T>.D OptionParserFor<T>(out Parser<T>.I parser)
where T : struct
{
parser = Substitute.For<IOptionParser<T>>();
parser.Parse<Tokenizer>(default!, default!)
.ReturnsForAnyArgs(0.Empty<T>());

var result = Substitute.For<Parser<IOptionParser<T>, T>.D>();
result().Returns(parser);

return result;
}

protected static Parser<IEnumParser<T>, T>.D EnumParserFor<T>()
where T : struct
=> EnumParserFor<T>(out var _);

protected static Parser<IEnumParser<T>, T>.D EnumParserFor<T>(out Parser<T>.I parser)
where T : struct
{
parser = Substitute.For<IEnumParser<T>>();
parser.Parse<Tokenizer>(default!, default!)
.ReturnsForAnyArgs(0.Empty<T>());

var result = Substitute.For<Parser<IEnumParser<T>, T>.D>();
result().Returns(parser);

return result;
}

protected static Parser<T>.DA ArrayParserFor<T>()
=> ArrayParserFor<T>(out var _);

protected static Parser<T>.DA ArrayParserFor<T>(out Parser<T>.IA parser)
{
parser = Substitute.For<Parser<T>.IA>();
parser.Parse<Tokenizer>(default!, default!)
.ReturnsForAnyArgs(0.EmptyArray<T>());

var result = Substitute.For<Parser<T>.DA>();
result().Returns(parser);

return result;
}
}
29 changes: 29 additions & 0 deletions test/GqlPlus.Verifier.ClassTests/Parse/ParseScalarClassTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using GqlPlus.Verifier.Ast;
using GqlPlus.Verifier.Ast.Schema;
using GqlPlus.Verifier.Result;
using NSubstitute;

namespace GqlPlus.Verifier.Parse.Schema;

public class ParseScalarClassTests : ClassTestBase
{
[Theory, RepeatData(Repeats)]
public void Parse_UnknownKind_ReturnsExpected(string name)
{
var tokens = Tokens("{ ");

var simpleName = NameFor<ISimpleName>(name);
var param = ArrayParserFor<NullAst>();
var aliases = ArrayParserFor<string>();
var option = OptionParserFor<NullOption>();
var definition = ParserFor<ScalarDefinition>(out var definitionParser);
definitionParser.Parse(tokens, default!)
.ReturnsForAnyArgs(new ScalarDefinition() { Kind = (ScalarKind)99 }.Ok());

var scalar = new ParseScalar(simpleName, param, aliases, option, definition);

var result = scalar.Parse(tokens, "test");

result.Should().BeAssignableTo<IResultOk<ScalarDeclAst>>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using GqlPlus.Verifier.Ast.Schema;
using GqlPlus.Verifier.Result;
using NSubstitute;

namespace GqlPlus.Verifier.Parse.Schema;

public class ParseScalarDefinitionClassTests : ClassTestBase
{
[Fact]
public void Parse_UnknownKind_ReturnsExpected()
{
var tokens = Tokens("{ ");

var kind = EnumParserFor<ScalarKind>(out var kindParser);
kindParser.Parse(tokens, default!)
.ReturnsForAnyArgs(((ScalarKind)99).Ok());

var ranges = ArrayParserFor<ScalarRangeAst>();
var references = ArrayParserFor<ScalarReferenceAst>();
var regexes = ArrayParserFor<ScalarRegexAst>();

var scalar = new ParseScalarDefinition(kind, ranges, references, regexes);

var result = scalar.Parse(tokens, "test");

result.Should().BeAssignableTo<IResultPartial<ScalarDefinition>>();
}
}
27 changes: 24 additions & 3 deletions test/GqlPlus.Verifier.ClassTests/Result/ResultTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,32 @@ public void Optional_ThrowsInvalidOperation()
.Which.Message.Should().Contain(nameof(String));
}

[Fact]
public void OptionalArray_ThrowsInvalidOperation()
{
var input = new TestResultArray<string>();

Action action = () => input.Optional();

action.Should().Throw<InvalidOperationException>()
.Which.Message.Should().Contain(nameof(String));
}

[ExcludeFromCodeCoverage]
public class TestResult<T> : IResult<T>
{
public IResult<R> AsPartial<R>(R result, Action<T>? withValue = null, Action? action = null) => throw new InvalidOperationException();
public IResult<R> AsResult<R>(R? _ = default) => throw new InvalidOperationException();
public IResult<R> Map<R>(SelectResult<T, R> onValue, OnResult<R>? otherwise = null) => throw new InvalidOperationException();
public IResult<R> AsPartial<R>(R result, Action<T>? withValue = null, Action? action = null) => throw new NotImplementedException();
public IResult<R> AsResult<R>(R? _ = default) => throw new NotImplementedException();
public IResult<R> Map<R>(SelectResult<T, R> onValue, OnResult<R>? otherwise = null) => throw new NotImplementedException();
}

[ExcludeFromCodeCoverage]
public class TestResultArray<T> : IResultArray<T>
{
public IResult<R> AsPartial<R>(R result, Action<T[]>? withValue = null, Action? action = null) => throw new NotImplementedException();
public IResultArray<R> AsPartialArray<R>(IEnumerable<R> result, Action<T[]>? withValue = null) => throw new NotImplementedException();
public IResult<R> AsResult<R>(R? _ = default) => throw new NotImplementedException();
public IResultArray<R> AsResultArray<R>(R[]? _ = null) => throw new NotImplementedException();
public IResult<R> Map<R>(SelectResult<T[], R> onValue, OnResult<R>? otherwise = null) => throw new NotImplementedException();
}
}

0 comments on commit 2c370d0

Please sign in to comment.