Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7601fe4

Browse files
Add unit tests to cover primitive methods on QueryExpression types (#1751)
1 parent cd8ae40 commit 7601fe4

File tree

3 files changed

+369
-14
lines changed

3 files changed

+369
-14
lines changed

‎src/JsonApiDotNetCore/Queries/Expressions/LogicalExpression.cs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ public LogicalExpression(LogicalOperator @operator, IImmutableList<FilterExpress
5252
{
5353
ArgumentNullException.ThrowIfNull(filters);
5454

55-
// Workaround for https://youtrack.jetbrains.com/issue/RSRP-496512/Invalid-Use-collection-expression-suggestion.
56-
// ReSharper disable once UseCollectionExpression
57-
ImmutableArray<FilterExpression> terms = filters.WhereNotNull().ToImmutableArray();
55+
ImmutableArray<FilterExpression> terms = [.. filters.WhereNotNull()];
5856

5957
return terms.Length > 1 ? new LogicalExpression(@operator, terms) : terms.FirstOrDefault();
6058
}

‎src/JsonApiDotNetCore/Queries/Expressions/NullConstantExpression.cs‎

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,7 @@ public override string ToFullString()
3535

3636
public override bool Equals(object? obj)
3737
{
38-
if (ReferenceEquals(this, obj))
39-
{
40-
return true;
41-
}
42-
43-
if (obj is null || GetType() != obj.GetType())
44-
{
45-
return false;
46-
}
47-
48-
return true;
38+
return ReferenceEquals(this, obj);
4939
}
5040

5141
public override int GetHashCode()
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
using System.Collections.Immutable;
2+
using FluentAssertions;
3+
using JetBrains.Annotations;
4+
using JsonApiDotNetCore.Configuration;
5+
using JsonApiDotNetCore.Queries.Expressions;
6+
using JsonApiDotNetCore.Resources;
7+
using JsonApiDotNetCore.Resources.Annotations;
8+
using Microsoft.Extensions.Logging.Abstractions;
9+
using Microsoft.Extensions.Primitives;
10+
using Xunit;
11+
12+
namespace JsonApiDotNetCoreTests.UnitTests.Queries;
13+
14+
public sealed class QueryExpressionTests
15+
{
16+
public static IEnumerable<object[]> ExpressionTestData =>
17+
new QueryExpression[][]
18+
{
19+
[
20+
TestExpressionFactory.Instance.Any(),
21+
TestExpressionFactory.Instance.Any()
22+
],
23+
[
24+
TestExpressionFactory.Instance.Comparison(),
25+
TestExpressionFactory.Instance.Comparison()
26+
],
27+
[
28+
TestExpressionFactory.Instance.Count(),
29+
TestExpressionFactory.Instance.Count()
30+
],
31+
[
32+
TestExpressionFactory.Instance.Has(),
33+
TestExpressionFactory.Instance.Has()
34+
],
35+
[
36+
TestExpressionFactory.Instance.IncludeElement(),
37+
TestExpressionFactory.Instance.IncludeElement()
38+
],
39+
[
40+
TestExpressionFactory.Instance.Include(),
41+
TestExpressionFactory.Instance.Include()
42+
],
43+
[
44+
TestExpressionFactory.Instance.IsType(),
45+
TestExpressionFactory.Instance.IsType()
46+
],
47+
[
48+
TestExpressionFactory.Instance.LiteralConstant(),
49+
TestExpressionFactory.Instance.LiteralConstant()
50+
],
51+
[
52+
TestExpressionFactory.Instance.Logical(),
53+
TestExpressionFactory.Instance.Logical()
54+
],
55+
[
56+
TestExpressionFactory.Instance.MatchText(),
57+
TestExpressionFactory.Instance.MatchText()
58+
],
59+
[
60+
TestExpressionFactory.Instance.Not(),
61+
TestExpressionFactory.Instance.Not()
62+
],
63+
[
64+
TestExpressionFactory.Instance.NullConstant(),
65+
TestExpressionFactory.Instance.NullConstant()
66+
],
67+
[
68+
TestExpressionFactory.Instance.PaginationElementQueryStringValue(),
69+
TestExpressionFactory.Instance.PaginationElementQueryStringValue()
70+
],
71+
[
72+
TestExpressionFactory.Instance.Pagination(),
73+
TestExpressionFactory.Instance.Pagination()
74+
],
75+
[
76+
TestExpressionFactory.Instance.PaginationQueryStringValue(),
77+
TestExpressionFactory.Instance.PaginationQueryStringValue()
78+
],
79+
[
80+
TestExpressionFactory.Instance.QueryableHandler(),
81+
TestExpressionFactory.Instance.QueryableHandler()
82+
],
83+
[
84+
TestExpressionFactory.Instance.QueryStringParameterScope(),
85+
TestExpressionFactory.Instance.QueryStringParameterScope()
86+
],
87+
[
88+
TestExpressionFactory.Instance.ResourceFieldChainForText(),
89+
TestExpressionFactory.Instance.ResourceFieldChainForText()
90+
],
91+
[
92+
TestExpressionFactory.Instance.ResourceFieldChainForParent(),
93+
TestExpressionFactory.Instance.ResourceFieldChainForParent()
94+
],
95+
[
96+
TestExpressionFactory.Instance.ResourceFieldChainForChildren(),
97+
TestExpressionFactory.Instance.ResourceFieldChainForChildren()
98+
],
99+
[
100+
TestExpressionFactory.Instance.SortElement(),
101+
TestExpressionFactory.Instance.SortElement()
102+
],
103+
[
104+
TestExpressionFactory.Instance.Sort(),
105+
TestExpressionFactory.Instance.Sort()
106+
],
107+
[
108+
TestExpressionFactory.Instance.SparseFieldSet(),
109+
TestExpressionFactory.Instance.SparseFieldSet()
110+
],
111+
[
112+
TestExpressionFactory.Instance.SparseFieldTable(),
113+
TestExpressionFactory.Instance.SparseFieldTable()
114+
]
115+
};
116+
117+
[Theory]
118+
[MemberData(nameof(ExpressionTestData))]
119+
public void Expressions_are_equal(QueryExpression left, QueryExpression right)
120+
{
121+
// Assert
122+
left.Equals(right).Should().BeTrue();
123+
right.Equals(left).Should().BeTrue();
124+
125+
// ReSharper disable once EqualExpressionComparison
126+
left.Equals(left).Should().BeTrue();
127+
}
128+
129+
[Theory]
130+
[MemberData(nameof(ExpressionTestData))]
131+
public void Expressions_are_not_equal_to_null(QueryExpression left, QueryExpression right)
132+
{
133+
// Assert
134+
left.Equals(null).Should().BeFalse();
135+
right.Equals(null).Should().BeFalse();
136+
}
137+
138+
[Theory]
139+
[MemberData(nameof(ExpressionTestData))]
140+
public void Expressions_have_same_hash_code(QueryExpression left, QueryExpression right)
141+
{
142+
// Assert
143+
left.GetHashCode().Should().Be(right.GetHashCode());
144+
}
145+
146+
[Theory]
147+
[MemberData(nameof(ExpressionTestData))]
148+
public void Expressions_convert_to_same_string(QueryExpression left, QueryExpression right)
149+
{
150+
// Assert
151+
left.ToString().Should().Be(right.ToString());
152+
}
153+
154+
[Theory]
155+
[MemberData(nameof(ExpressionTestData))]
156+
public void Expressions_convert_to_same_full_string(QueryExpression left, QueryExpression right)
157+
{
158+
// Assert
159+
left.ToFullString().Should().Be(right.ToFullString());
160+
}
161+
162+
[Theory]
163+
[MemberData(nameof(ExpressionTestData))]
164+
public void Expressions_have_same_return_type(QueryExpression left, QueryExpression right)
165+
{
166+
if (left is FunctionExpression leftFunction && right is FunctionExpression rightFunction)
167+
{
168+
// Assert
169+
leftFunction.ReturnType.Should().Be(rightFunction.ReturnType);
170+
}
171+
}
172+
173+
[Theory]
174+
[MemberData(nameof(ExpressionTestData))]
175+
public void Expressions_can_accept_visitor(QueryExpression left, QueryExpression right)
176+
{
177+
// Assert
178+
left.Accept(EmptyQueryExpressionVisitor.Instance, null).Should().BeNull();
179+
right.Accept(EmptyQueryExpressionVisitor.Instance, null).Should().BeNull();
180+
}
181+
182+
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
183+
private class BaseTestResource : Identifiable<Guid>
184+
{
185+
[Attr]
186+
public string? Text { get; set; }
187+
188+
[HasOne]
189+
public BaseTestResource? Parent { get; set; }
190+
191+
[HasMany]
192+
public ISet<BaseTestResource> Children { get; set; } = new HashSet<BaseTestResource>();
193+
}
194+
195+
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
196+
private sealed class DerivedTestResource : BaseTestResource;
197+
198+
private sealed class TestExpressionFactory
199+
{
200+
private readonly ResourceType _baseTestResourceType;
201+
private readonly ResourceType _derivedTestResourceType;
202+
private readonly AttrAttribute _textAttribute;
203+
private readonly RelationshipAttribute _parentRelationship;
204+
private readonly RelationshipAttribute _childrenRelationship;
205+
public static TestExpressionFactory Instance { get; } = new();
206+
207+
private TestExpressionFactory()
208+
{
209+
var options = new JsonApiOptions();
210+
211+
var builder = new ResourceGraphBuilder(options, NullLoggerFactory.Instance);
212+
builder.Add<BaseTestResource, Guid>();
213+
builder.Add<DerivedTestResource, Guid>();
214+
IResourceGraph resourceGraph = builder.Build();
215+
216+
_baseTestResourceType = resourceGraph.GetResourceType<BaseTestResource>();
217+
_derivedTestResourceType = resourceGraph.GetResourceType<DerivedTestResource>();
218+
_textAttribute = _baseTestResourceType.GetAttributeByPropertyName(nameof(BaseTestResource.Text));
219+
_parentRelationship = _baseTestResourceType.GetRelationshipByPropertyName(nameof(BaseTestResource.Parent));
220+
_childrenRelationship = _baseTestResourceType.GetRelationshipByPropertyName(nameof(BaseTestResource.Children));
221+
}
222+
223+
public AnyExpression Any()
224+
{
225+
return new AnyExpression(ResourceFieldChainForText(), [LiteralConstant()]);
226+
}
227+
228+
public ComparisonExpression Comparison()
229+
{
230+
return new ComparisonExpression(ComparisonOperator.Equals, ResourceFieldChainForText(), LiteralConstant());
231+
}
232+
233+
public CountExpression Count()
234+
{
235+
return new CountExpression(ResourceFieldChainForChildren());
236+
}
237+
238+
public HasExpression Has()
239+
{
240+
return new HasExpression(ResourceFieldChainForChildren(), Comparison());
241+
}
242+
243+
public IncludeElementExpression IncludeElement()
244+
{
245+
return new IncludeElementExpression(_parentRelationship, [new IncludeElementExpression(_childrenRelationship)]);
246+
}
247+
248+
public IncludeExpression Include()
249+
{
250+
return new IncludeExpression([IncludeElement()]);
251+
}
252+
253+
public IsTypeExpression IsType()
254+
{
255+
return new IsTypeExpression(ResourceFieldChainForParent(), _derivedTestResourceType, Has());
256+
}
257+
258+
public LiteralConstantExpression LiteralConstant()
259+
{
260+
return new LiteralConstantExpression("example");
261+
}
262+
263+
public LogicalExpression Logical()
264+
{
265+
return new LogicalExpression(LogicalOperator.Or, Comparison(), MatchText());
266+
}
267+
268+
public MatchTextExpression MatchText()
269+
{
270+
return new MatchTextExpression(ResourceFieldChainForText(), LiteralConstant(), TextMatchKind.Contains);
271+
}
272+
273+
public NotExpression Not()
274+
{
275+
return new NotExpression(Comparison());
276+
}
277+
278+
public NullConstantExpression NullConstant()
279+
{
280+
return NullConstantExpression.Instance;
281+
}
282+
283+
public PaginationElementQueryStringValueExpression PaginationElementQueryStringValue()
284+
{
285+
return new PaginationElementQueryStringValueExpression(ResourceFieldChainForChildren(), 5, 8);
286+
}
287+
288+
public PaginationExpression Pagination()
289+
{
290+
return new PaginationExpression(new PageNumber(2), new PageSize(5));
291+
}
292+
293+
public PaginationQueryStringValueExpression PaginationQueryStringValue()
294+
{
295+
return new PaginationQueryStringValueExpression([PaginationElementQueryStringValue()]);
296+
}
297+
298+
public QueryableHandlerExpression QueryableHandler()
299+
{
300+
#pragma warning disable CS8974 // Converting method group to non-delegate type
301+
object handler = TestQueryableHandler;
302+
#pragma warning restore CS8974 // Converting method group to non-delegate type
303+
return new QueryableHandlerExpression(handler, "disableCache");
304+
}
305+
306+
public QueryStringParameterScopeExpression QueryStringParameterScope()
307+
{
308+
return new QueryStringParameterScopeExpression(LiteralConstant(), ResourceFieldChainForChildren());
309+
}
310+
311+
public ResourceFieldChainExpression ResourceFieldChainForText()
312+
{
313+
return new ResourceFieldChainExpression(_textAttribute);
314+
}
315+
316+
public ResourceFieldChainExpression ResourceFieldChainForParent()
317+
{
318+
return new ResourceFieldChainExpression([_parentRelationship]);
319+
}
320+
321+
public ResourceFieldChainExpression ResourceFieldChainForChildren()
322+
{
323+
return new ResourceFieldChainExpression([_childrenRelationship]);
324+
}
325+
326+
public SortElementExpression SortElement()
327+
{
328+
return new SortElementExpression(Count(), false);
329+
}
330+
331+
public SortExpression Sort()
332+
{
333+
return new SortExpression([SortElement()]);
334+
}
335+
336+
public SparseFieldSetExpression SparseFieldSet()
337+
{
338+
return new SparseFieldSetExpression([
339+
_textAttribute,
340+
_childrenRelationship
341+
]);
342+
}
343+
344+
public SparseFieldTableExpression SparseFieldTable()
345+
{
346+
return new SparseFieldTableExpression(new Dictionary<ResourceType, SparseFieldSetExpression>
347+
{
348+
[_baseTestResourceType] = SparseFieldSet(),
349+
[_derivedTestResourceType] = SparseFieldSet()
350+
}.ToImmutableDictionary());
351+
}
352+
353+
private static IQueryable<BaseTestResource> TestQueryableHandler(IQueryable<BaseTestResource> source, StringValues parameterValue)
354+
{
355+
throw new NotImplementedException();
356+
}
357+
}
358+
359+
private sealed class EmptyQueryExpressionVisitor : QueryExpressionVisitor<BaseTestResource?, object?>
360+
{
361+
public static EmptyQueryExpressionVisitor Instance { get; } = new();
362+
363+
private EmptyQueryExpressionVisitor()
364+
{
365+
}
366+
}
367+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /