Skip to content

Commit 6738a09

Browse files
author
Bart Koelman
committed
Added rewriter unit tests to improve code coverage
1 parent 0333a01 commit 6738a09

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
using System.Collections.Immutable;
2+
using System.ComponentModel.Design;
3+
using FluentAssertions;
4+
using JsonApiDotNetCore.Configuration;
5+
using JsonApiDotNetCore.Queries.Expressions;
6+
using JsonApiDotNetCore.Queries.Internal.Parsing;
7+
using JsonApiDotNetCore.Resources;
8+
using JsonApiDotNetCoreTests.IntegrationTests.QueryStrings;
9+
using Microsoft.Extensions.Logging.Abstractions;
10+
using Xunit;
11+
12+
namespace JsonApiDotNetCoreTests.UnitTests.Queries;
13+
14+
public sealed class QueryExpressionRewriterTests
15+
{
16+
private static readonly IResourceFactory ResourceFactory = new ResourceFactory(new ServiceContainer());
17+
18+
// @formatter:wrap_chained_method_calls chop_always
19+
// @formatter:keep_existing_linebreaks true
20+
21+
private static readonly IResourceGraph ResourceGraph = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance)
22+
.Add<Blog, int>()
23+
.Add<BlogPost, int>()
24+
.Add<Label, int>()
25+
.Add<Comment, int>()
26+
.Add<WebAccount, int>()
27+
.Add<Human, int>()
28+
.Add<Man, int>()
29+
.Add<Woman, int>()
30+
.Add<AccountPreferences, int>()
31+
.Add<LoginAttempt, int>()
32+
.Build();
33+
34+
// @formatter:wrap_chained_method_calls restore
35+
// @formatter:keep_existing_linebreaks restore
36+
37+
[Theory]
38+
[InlineData("posts", "Include,IncludeElement")]
39+
[InlineData("posts.comments,owner.loginAttempts", "Include,IncludeElement,IncludeElement,IncludeElement,IncludeElement")]
40+
public void VisitInclude(string expressionText, string expectedTypes)
41+
{
42+
// Arrange
43+
var parser = new IncludeParser();
44+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
45+
46+
QueryExpression expression = parser.Parse(expressionText, blogType, null);
47+
var rewriter = new TestableQueryExpressionRewriter();
48+
49+
// Act
50+
rewriter.Visit(expression, null);
51+
52+
// Assert
53+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
54+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
55+
56+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
57+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
58+
}
59+
60+
[Theory]
61+
[InlineData("title", "SparseFieldSet")]
62+
[InlineData("title,posts", "SparseFieldSet")]
63+
public void VisitSparseFieldSet(string expressionText, string expectedTypes)
64+
{
65+
// Arrange
66+
var parser = new SparseFieldSetParser();
67+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
68+
69+
QueryExpression expression = parser.Parse(expressionText, blogType)!;
70+
var rewriter = new TestableQueryExpressionRewriter();
71+
72+
// Act
73+
rewriter.Visit(expression, null);
74+
75+
// Assert
76+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
77+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
78+
79+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
80+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
81+
}
82+
83+
[Fact]
84+
public void VisitSparseFieldTable()
85+
{
86+
// Arrange
87+
var parser = new SparseFieldSetParser();
88+
89+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
90+
ResourceType commentType = ResourceGraph.GetResourceType<Comment>();
91+
92+
var sparseFieldTable = new Dictionary<ResourceType, SparseFieldSetExpression>
93+
{
94+
[blogType] = parser.Parse("title,owner", blogType)!,
95+
[commentType] = parser.Parse("text,createdAt", commentType)!
96+
};
97+
98+
var expression = new SparseFieldTableExpression(sparseFieldTable.ToImmutableDictionary());
99+
var rewriter = new TestableQueryExpressionRewriter();
100+
101+
// Act
102+
rewriter.Visit(expression, null);
103+
104+
// Assert
105+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
106+
107+
visitedTypeNames.Should().HaveCount(3);
108+
visitedTypeNames[0].Should().Be("SparseFieldTableExpression");
109+
visitedTypeNames[1].Should().Be("SparseFieldSetExpression");
110+
visitedTypeNames[2].Should().Be("SparseFieldSetExpression");
111+
}
112+
113+
[Theory]
114+
[InlineData("any(userName,'A','B')", "Any,ResourceFieldChain,LiteralConstant,LiteralConstant")]
115+
[InlineData("equals(userName,null)", "Comparison,ResourceFieldChain,NullConstant")]
116+
[InlineData("has(loginAttempts)", "Has,ResourceFieldChain")]
117+
[InlineData("has(loginAttempts,equals(isSucceeded,'true'))", "Has,ResourceFieldChain,Comparison,ResourceFieldChain,LiteralConstant")]
118+
[InlineData("isType(person,men)", "IsType,ResourceFieldChain")]
119+
[InlineData("isType(person,men,greaterThan(age,'18'))", "IsType,ResourceFieldChain,Comparison,ResourceFieldChain,LiteralConstant")]
120+
[InlineData("and(equals(userName,null),has(loginAttempts))", "Logical,Comparison,ResourceFieldChain,NullConstant,Has,ResourceFieldChain")]
121+
[InlineData("startsWith(userName,'A')", "MatchText,ResourceFieldChain,LiteralConstant")]
122+
[InlineData("not(equals(count(loginAttempts),'1'))", "Not,Comparison,Count,ResourceFieldChain,LiteralConstant")]
123+
public void VisitFilter(string expressionText, string expectedTypes)
124+
{
125+
// Arrange
126+
var parser = new FilterParser(ResourceFactory);
127+
ResourceType webAccountType = ResourceGraph.GetResourceType<WebAccount>();
128+
129+
QueryExpression expression = parser.Parse(expressionText, webAccountType);
130+
var rewriter = new TestableQueryExpressionRewriter();
131+
132+
// Act
133+
rewriter.Visit(expression, null);
134+
135+
// Assert
136+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
137+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
138+
139+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
140+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
141+
}
142+
143+
[Theory]
144+
[InlineData("title", "Sort,SortElement,ResourceFieldChain")]
145+
[InlineData("title,-platformName", "Sort,SortElement,ResourceFieldChain,SortElement,ResourceFieldChain")]
146+
[InlineData("count(posts)", "Sort,SortElement,Count,ResourceFieldChain")]
147+
public void VisitSort(string expressionText, string expectedTypes)
148+
{
149+
// Arrange
150+
var parser = new SortParser();
151+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
152+
153+
QueryExpression expression = parser.Parse(expressionText, blogType);
154+
var rewriter = new TestableQueryExpressionRewriter();
155+
156+
// Act
157+
rewriter.Visit(expression, null);
158+
159+
// Assert
160+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
161+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
162+
163+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
164+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
165+
}
166+
167+
[Theory]
168+
[InlineData("2", "PaginationQueryStringValue,PaginationElementQueryStringValue")]
169+
[InlineData("posts:3,2", "PaginationQueryStringValue,PaginationElementQueryStringValue,ResourceFieldChain,PaginationElementQueryStringValue")]
170+
public void VisitPagination(string expressionText, string expectedTypes)
171+
{
172+
// Arrange
173+
var parser = new PaginationParser();
174+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
175+
176+
QueryExpression expression = parser.Parse(expressionText, blogType);
177+
var rewriter = new TestableQueryExpressionRewriter();
178+
179+
// Act
180+
rewriter.Visit(expression, null);
181+
182+
// Assert
183+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
184+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
185+
186+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
187+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
188+
}
189+
190+
[Theory]
191+
[InlineData("filter", "QueryStringParameterScope,LiteralConstant")]
192+
[InlineData("filter[posts.comments]", "QueryStringParameterScope,LiteralConstant,ResourceFieldChain")]
193+
public void VisitParameterScope(string expressionText, string expectedTypes)
194+
{
195+
// Arrange
196+
var parser = new QueryStringParameterScopeParser(FieldChainRequirements.EndsInToMany);
197+
ResourceType blogType = ResourceGraph.GetResourceType<Blog>();
198+
199+
QueryExpression expression = parser.Parse(expressionText, blogType);
200+
var rewriter = new TestableQueryExpressionRewriter();
201+
202+
// Act
203+
rewriter.Visit(expression, null);
204+
205+
// Assert
206+
List<string> visitedTypeNames = rewriter.ExpressionsVisited.Select(queryExpression => queryExpression.GetType().Name).ToList();
207+
List<string> expectedTypeNames = expectedTypes.Split(',').Select(type => type + "Expression").ToList();
208+
209+
visitedTypeNames.Should().ContainInOrder(expectedTypeNames);
210+
visitedTypeNames.Should().HaveCount(expectedTypeNames.Count);
211+
}
212+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
using JsonApiDotNetCore.Queries.Expressions;
2+
3+
namespace JsonApiDotNetCoreTests.UnitTests.Queries;
4+
5+
internal sealed class TestableQueryExpressionRewriter : QueryExpressionRewriter<object?>
6+
{
7+
public List<QueryExpression> ExpressionsVisited { get; } = new();
8+
9+
public override QueryExpression DefaultVisit(QueryExpression expression, object? argument)
10+
{
11+
Capture(expression);
12+
return base.DefaultVisit(expression, argument);
13+
}
14+
15+
public override QueryExpression? VisitComparison(ComparisonExpression expression, object? argument)
16+
{
17+
Capture(expression);
18+
return base.VisitComparison(expression, argument);
19+
}
20+
21+
public override QueryExpression? VisitResourceFieldChain(ResourceFieldChainExpression expression, object? argument)
22+
{
23+
Capture(expression);
24+
return base.VisitResourceFieldChain(expression, argument);
25+
}
26+
27+
public override QueryExpression VisitLiteralConstant(LiteralConstantExpression expression, object? argument)
28+
{
29+
Capture(expression);
30+
return base.VisitLiteralConstant(expression, argument);
31+
}
32+
33+
public override QueryExpression VisitNullConstant(NullConstantExpression expression, object? argument)
34+
{
35+
Capture(expression);
36+
return base.VisitNullConstant(expression, argument);
37+
}
38+
39+
public override QueryExpression? VisitLogical(LogicalExpression expression, object? argument)
40+
{
41+
Capture(expression);
42+
return base.VisitLogical(expression, argument);
43+
}
44+
45+
public override QueryExpression? VisitNot(NotExpression expression, object? argument)
46+
{
47+
Capture(expression);
48+
return base.VisitNot(expression, argument);
49+
}
50+
51+
public override QueryExpression? VisitHas(HasExpression expression, object? argument)
52+
{
53+
Capture(expression);
54+
return base.VisitHas(expression, argument);
55+
}
56+
57+
public override QueryExpression VisitIsType(IsTypeExpression expression, object? argument)
58+
{
59+
Capture(expression);
60+
return base.VisitIsType(expression, argument);
61+
}
62+
63+
public override QueryExpression? VisitSortElement(SortElementExpression expression, object? argument)
64+
{
65+
Capture(expression);
66+
return base.VisitSortElement(expression, argument);
67+
}
68+
69+
public override QueryExpression? VisitSort(SortExpression expression, object? argument)
70+
{
71+
Capture(expression);
72+
return base.VisitSort(expression, argument);
73+
}
74+
75+
public override QueryExpression VisitPagination(PaginationExpression expression, object? argument)
76+
{
77+
Capture(expression);
78+
return base.VisitPagination(expression, argument);
79+
}
80+
81+
public override QueryExpression? VisitCount(CountExpression expression, object? argument)
82+
{
83+
Capture(expression);
84+
return base.VisitCount(expression, argument);
85+
}
86+
87+
public override QueryExpression? VisitMatchText(MatchTextExpression expression, object? argument)
88+
{
89+
Capture(expression);
90+
return base.VisitMatchText(expression, argument);
91+
}
92+
93+
public override QueryExpression? VisitAny(AnyExpression expression, object? argument)
94+
{
95+
Capture(expression);
96+
return base.VisitAny(expression, argument);
97+
}
98+
99+
public override QueryExpression? VisitSparseFieldTable(SparseFieldTableExpression expression, object? argument)
100+
{
101+
Capture(expression);
102+
return base.VisitSparseFieldTable(expression, argument);
103+
}
104+
105+
public override QueryExpression VisitSparseFieldSet(SparseFieldSetExpression expression, object? argument)
106+
{
107+
Capture(expression);
108+
return base.VisitSparseFieldSet(expression, argument);
109+
}
110+
111+
public override QueryExpression? VisitQueryStringParameterScope(QueryStringParameterScopeExpression expression, object? argument)
112+
{
113+
Capture(expression);
114+
return base.VisitQueryStringParameterScope(expression, argument);
115+
}
116+
117+
public override QueryExpression PaginationQueryStringValue(PaginationQueryStringValueExpression expression, object? argument)
118+
{
119+
Capture(expression);
120+
return base.PaginationQueryStringValue(expression, argument);
121+
}
122+
123+
public override QueryExpression PaginationElementQueryStringValue(PaginationElementQueryStringValueExpression expression, object? argument)
124+
{
125+
Capture(expression);
126+
return base.PaginationElementQueryStringValue(expression, argument);
127+
}
128+
129+
public override QueryExpression VisitInclude(IncludeExpression expression, object? argument)
130+
{
131+
Capture(expression);
132+
return base.VisitInclude(expression, argument);
133+
}
134+
135+
public override QueryExpression VisitIncludeElement(IncludeElementExpression expression, object? argument)
136+
{
137+
Capture(expression);
138+
return base.VisitIncludeElement(expression, argument);
139+
}
140+
141+
public override QueryExpression VisitQueryableHandler(QueryableHandlerExpression expression, object? argument)
142+
{
143+
Capture(expression);
144+
return base.VisitQueryableHandler(expression, argument);
145+
}
146+
147+
private void Capture(QueryExpression expression)
148+
{
149+
ExpressionsVisited.Add(expression);
150+
}
151+
}

0 commit comments

Comments
 (0)