Skip to content

Commit 9000421

Browse files
committed
chore: re-add unit test for defaultentityrepository for test IAsyncQueryProvider that's actually a List
1 parent 9ee71f5 commit 9000421

File tree

9 files changed

+126
-104
lines changed

9 files changed

+126
-104
lines changed

src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public Dictionary<string, object> GetMeta()
3131
{
3232
return new Dictionary<string, object> {
3333
{ "copyright", "Copyright 2015 Example Corp." },
34-
{ "authors", new string[] { "Jared Nance", "Maurits Moeys" } }
34+
{ "authors", new string[] { "Jared Nance", "Maurits Moeys", "Harro van der Kroft" } }
3535
};
3636
}
3737
}

src/JsonApiDotNetCore/Data/DefaultResourceRepository.cs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using JsonApiDotNetCore.Models;
1111
using JsonApiDotNetCore.Serialization;
1212
using Microsoft.EntityFrameworkCore;
13+
using Microsoft.EntityFrameworkCore.Query.Internal;
1314
using Microsoft.Extensions.Logging;
1415

1516
namespace JsonApiDotNetCore.Data
@@ -298,21 +299,43 @@ public virtual IQueryable<TResource> Include(IQueryable<TResource> entities, IEn
298299
/// <inheritdoc />
299300
public virtual async Task<IEnumerable<TResource>> PageAsync(IQueryable<TResource> entities, int pageSize, int pageNumber)
300301
{
302+
// the IQueryable returned from the hook executor is sometimes consumed here.
303+
// In this case, it does not support .ToListAsync(), so we use the method below.
301304
if (pageNumber >= 0)
302305
{
303-
// the IQueryable returned from the hook executor is sometimes consumed here.
304-
// In this case, it does not support .ToListAsync(), so we use the method below.
305-
return await this.ToListAsync(entities.PageForward(pageSize, pageNumber));
306+
entities = entities.PageForward(pageSize, pageNumber);
307+
if (entities is IAsyncQueryProvider)
308+
{
309+
return await entities.ToListAsync();
310+
}
311+
else
312+
{
313+
return entities.ToList();
314+
}
315+
}
316+
else
317+
{
318+
if (!(entities is IAsyncQueryProvider))
319+
{
320+
entities = entities.Reverse();
321+
int firstIndex = pageSize * Math.Abs(pageNumber) - 1;
322+
int numberOfElementsInPage = Math.Min(pageSize, firstIndex + pageSize);
323+
324+
return entities.Skip(firstIndex).Take(numberOfElementsInPage);
325+
}
326+
else
327+
{
328+
// since EntityFramework does not support IQueryable.Reverse(), we need to know the number of queried entities
329+
var totalCount = await entities.CountAsync();
330+
331+
int virtualFirstIndex = totalCount - pageSize * Math.Abs(pageNumber);
332+
int numberOfElementsInPage = Math.Min(pageSize, virtualFirstIndex + pageSize);
333+
334+
return await ToListAsync(entities
335+
.Skip(virtualFirstIndex)
336+
.Take(numberOfElementsInPage));
337+
}
306338
}
307-
// since EntityFramework does not support IQueryable.Reverse(), we need to know the number of queried entities
308-
var totalCount = await entities.CountAsync();
309-
// may be negative
310-
int virtualFirstIndex = totalCount - pageSize * Math.Abs(pageNumber);
311-
int numberOfElementsInPage = Math.Min(pageSize, virtualFirstIndex + pageSize);
312-
313-
return await ToListAsync(entities
314-
.Skip(virtualFirstIndex)
315-
.Take(numberOfElementsInPage));
316339
}
317340

318341
/// <inheritdoc />

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PagingTests.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,23 +95,20 @@ public async Task Can_Paginate_TodoItems_From_End()
9595
var totalCount = expectedEntitiesPerPage * 2;
9696
var person = new Person();
9797
var todoItems = _todoItemFaker.Generate(totalCount).ToList();
98-
99-
foreach (var todoItem in todoItems)
100-
todoItem.Owner = person;
98+
todoItems.ForEach(ti => ti.Owner = person);
10199

102100
Context.TodoItems.RemoveRange(Context.TodoItems);
103101
Context.TodoItems.AddRange(todoItems);
104102
Context.SaveChanges();
105-
106103
var route = $"/api/v1/todo-items?page[size]={expectedEntitiesPerPage}&page[number]=-1";
107104

108105
// Act
109106
var response = await Client.GetAsync(route);
110107

111108
// Assert
112-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
113-
114109
var body = await response.Content.ReadAsStringAsync();
110+
111+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
115112
var deserializedBody = _fixture.GetDeserializer().DeserializeList<TodoItem>(body).Data;
116113

117114
var expectedTodoItems = new[] { todoItems[totalCount - 2], todoItems[totalCount - 1] };

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public async Task Response400IfUpdatingNotSettableAttribute()
7070
public async Task Respond_404_If_EntityDoesNotExist()
7171
{
7272
// Arrange
73-
var maxPersonId = _context.TodoItems.LastOrDefault()?.Id ?? 0;
73+
var maxPersonId = _context.TodoItems.ToList().LastOrDefault()?.Id ?? 0;
7474
var todoItem = _todoItemFaker.Generate();
7575
todoItem.Id = maxPersonId + 100;
7676
todoItem.CreatedDate = DateTime.Now;
@@ -95,7 +95,7 @@ public async Task Respond_404_If_EntityDoesNotExist()
9595
public async Task Respond_422_If_IdNotInAttributeList()
9696
{
9797
// Arrange
98-
var maxPersonId = _context.TodoItems.LastOrDefault()?.Id ?? 0;
98+
var maxPersonId = _context.TodoItems.ToList().LastOrDefault()?.Id ?? 0;
9999
var todoItem = _todoItemFaker.Generate();
100100
todoItem.CreatedDate = DateTime.Now;
101101
var builder = new WebHostBuilder()

test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
using System.Net.Http;
44
using System.Net.Http.Headers;
55
using System.Threading.Tasks;
6+
using JsonApiDotNetCoreExample;
67
using JsonApiDotNetCoreExample.Models;
8+
using Microsoft.AspNetCore.Hosting;
9+
using Microsoft.AspNetCore.TestHost;
710
using Newtonsoft.Json;
811
using Xunit;
912

@@ -74,7 +77,6 @@ public async Task Can_Create_TodoItems()
7477
{
7578
// Arrange
7679
var description = Guid.NewGuid().ToString();
77-
var client = _fixture.Server.CreateClient();
7880
var httpMethod = new HttpMethod("POST");
7981
var route = $"/api/v1/custom-todo-items/";
8082
var content = new
@@ -94,6 +96,11 @@ public async Task Can_Create_TodoItems()
9496
request.Content = new StringContent(JsonConvert.SerializeObject(content));
9597
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json");
9698

99+
var builder = new WebHostBuilder()
100+
.UseStartup<Startup>();
101+
var server = new TestServer(builder);
102+
var client = server.CreateClient();
103+
97104
// Act
98105
var response = await client.SendAsync(request);
99106
var responseBody = await response.Content.ReadAsStringAsync();

test/NoEntityFrameworkTests/TestFixture.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using JsonApiDotNetCore.Builders;
22
using JsonApiDotNetCore.Models;
33
using JsonApiDotNetCore.Serialization.Client;
4+
using JsonApiDotNetCoreExample;
45
using JsonApiDotNetCoreExample.Data;
56
using JsonApiDotNetCoreExample.Models;
67
using JsonApiDotNetCoreExampleTests.Helpers.Extensions;
@@ -19,7 +20,7 @@ public class TestFixture : IDisposable
1920
private IServiceProvider _services;
2021
public TestFixture()
2122
{
22-
var builder = new WebHostBuilder().UseStartup<TestStartup>();
23+
var builder = new WebHostBuilder().UseStartup<Startup>();
2324
Server = new TestServer(builder);
2425
Context = Server.GetService<AppDbContext>();
2526
Context.Database.EnsureCreated();
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using JsonApiDotNetCore.Builders;
2+
using JsonApiDotNetCore.Data;
3+
using JsonApiDotNetCore.Internal.Contracts;
4+
using JsonApiDotNetCore.Serialization;
5+
using JsonApiDotNetCoreExample.Data;
6+
using JsonApiDotNetCoreExample.Models;
7+
using Microsoft.EntityFrameworkCore;
8+
using Moq;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Linq;
12+
using System.Text;
13+
using System.Threading.Tasks;
14+
using Xunit;
15+
16+
namespace UnitTests.Data
17+
{
18+
public class DefaultEntityRepositoryTest
19+
{
20+
21+
[Fact]
22+
public async Task PageAsync_IQueryableIsAListAndPageNumberPositive_CanStillCount()
23+
{
24+
// If IQueryable is actually a list (this can happen after a filter or hook)
25+
// It needs to not do CountAsync, because well.. its not asynchronous.
26+
27+
// Arrange
28+
var repository = Setup();
29+
var todoItems = new List<TodoItem>() {
30+
new TodoItem{ Id = 1 },
31+
new TodoItem{ Id = 2 }
32+
};
33+
34+
// Act
35+
var result = await repository.PageAsync(todoItems.AsQueryable(), pageSize: 1, pageNumber: 2);
36+
37+
// Assert
38+
Assert.True(result.ElementAt(0).Id == todoItems[1].Id);
39+
}
40+
41+
[Fact]
42+
public async Task PageAsync_IQueryableIsAListAndPageNumberNegative_CanStillCount()
43+
{
44+
// If IQueryable is actually a list (this can happen after a filter or hook)
45+
// It needs to not do CountAsync, because well.. its not asynchronous.
46+
47+
// Arrange
48+
var repository = Setup();
49+
var todoItems = new List<TodoItem>() {
50+
new TodoItem{ Id = 1 },
51+
new TodoItem{ Id = 2 },
52+
new TodoItem{ Id = 3 },
53+
new TodoItem{ Id = 4 }
54+
};
55+
56+
// Act
57+
var result = await repository.PageAsync(todoItems.AsQueryable(), pageSize: 1, pageNumber: -2);
58+
59+
// Assert
60+
Assert.True(result.First().Id == 3);
61+
}
62+
63+
private DefaultResourceRepository<TodoItem> Setup()
64+
{
65+
var contextResolverMock = new Mock<IDbContextResolver>();
66+
contextResolverMock.Setup(m => m.GetContext()).Returns(new Mock<DbContext>().Object);
67+
var resourceGraph = new Mock<IResourceGraph>();
68+
var targetedFields = new Mock<ITargetedFields>();
69+
var repository = new DefaultResourceRepository<TodoItem>(targetedFields.Object, contextResolverMock.Object, resourceGraph.Object, null);
70+
return repository;
71+
}
72+
73+
}
74+
}

test/UnitTests/Data/DefaultEntityRepositoryTests.cs

Lines changed: 0 additions & 81 deletions
This file was deleted.

test/UnitTests/UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
</None>
2424
</ItemGroup>
2525
<ItemGroup>
26+
<Folder Include="Repositories\" />
2627
<Folder Include="Serialization\Common\" />
2728
<Folder Include="Serialization\Client\" />
2829
<Folder Include="Serialization\Server\" />

0 commit comments

Comments
 (0)