Skip to content

Commit 009d3b5

Browse files
Merge branch 'main' into seo/83203-read-json
2 parents 783639f + e648dc4 commit 009d3b5

683 files changed

Lines changed: 18408 additions & 579 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

aspnetcore-webapi/AdvancedRestConceptsSeries/AdvancedRestConceptsSeries.sln

Lines changed: 651 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.11" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
12+
<PackageReference Include="Testcontainers.MsSql" Version="4.14.0" />
13+
<PackageReference Include="xunit" Version="2.9.3" />
14+
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
15+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
16+
<PrivateAssets>all</PrivateAssets>
17+
</PackageReference>
18+
<PackageReference Include="coverlet.collector" Version="6.0.4">
19+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20+
<PrivateAssets>all</PrivateAssets>
21+
</PackageReference>
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="..\AccountOwnerServer\AccountOwnerServer.csproj" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Entities.Helpers;
2+
using Entities.Models;
3+
using System.Linq;
4+
using Xunit;
5+
6+
namespace AccountOwnerServer.Tests;
7+
8+
public class DataShaperTests
9+
{
10+
private static readonly DataShaper<Owner> Shaper = new();
11+
12+
[Fact]
13+
public void GivenNoFields_WhenWeShape_ThenEveryPropertyIsKept()
14+
{
15+
var shaped = Shaper.ShapeData(SqlServerSample.Owners().First(), null);
16+
17+
Assert.Equal(4, shaped.Count);
18+
Assert.True(shaped.ContainsKey(nameof(Owner.Address)));
19+
}
20+
21+
[Fact]
22+
public void GivenASubsetOfFields_WhenWeShape_ThenOnlyThoseComeBack()
23+
{
24+
var shaped = Shaper.ShapeData(SqlServerSample.Owners().First(), "name,dateOfBirth");
25+
26+
Assert.Equal(2, shaped.Count);
27+
Assert.True(shaped.ContainsKey(nameof(Owner.Name)));
28+
Assert.False(shaped.ContainsKey(nameof(Owner.Address)));
29+
}
30+
31+
[Fact]
32+
public void GivenAFieldInAnyCasing_WhenWeShape_ThenItStillMatchesThePropertyName()
33+
{
34+
var shaped = Shaper.ShapeData(SqlServerSample.Owners().First(), "NAME");
35+
36+
Assert.True(shaped.ContainsKey(nameof(Owner.Name)));
37+
}
38+
39+
[Fact]
40+
public void GivenAnUnknownField_WhenWeShape_ThenItIsIgnored()
41+
{
42+
var shaped = Shaper.ShapeData(SqlServerSample.Owners().First(), "name,age");
43+
44+
Assert.Single(shaped);
45+
Assert.True(shaped.ContainsKey(nameof(Owner.Name)));
46+
}
47+
48+
[Fact]
49+
public void GivenACollection_WhenWeShape_ThenEveryEntityIsShaped()
50+
{
51+
var shaped = Shaper.ShapeData(SqlServerSample.Owners(), "name").ToList();
52+
53+
Assert.Equal(5, shaped.Count);
54+
Assert.All(shaped, s => Assert.Single(s));
55+
}
56+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Entities.Models;
2+
using Xunit;
3+
4+
namespace AccountOwnerServer.Tests;
5+
6+
public class OwnerParametersTests
7+
{
8+
[Fact]
9+
public void GivenTheSameMinAndMaxYear_WhenTheRangeIsValidated_ThenItIsAccepted()
10+
{
11+
var parameters = new OwnerParameters { MinYearOfBirth = 1990, MaxYearOfBirth = 1990 };
12+
13+
Assert.True(parameters.ValidYearRange);
14+
}
15+
16+
[Fact]
17+
public void GivenAMaxYearBelowTheMinYear_WhenTheRangeIsValidated_ThenItIsRejected()
18+
{
19+
var parameters = new OwnerParameters { MinYearOfBirth = 1975, MaxYearOfBirth = 1974 };
20+
21+
Assert.False(parameters.ValidYearRange);
22+
}
23+
24+
[Fact]
25+
public void GivenNoYearsAtAll_WhenTheRangeIsValidated_ThenItIsAccepted()
26+
{
27+
var parameters = new OwnerParameters();
28+
29+
Assert.Null(parameters.MinYearOfBirth);
30+
Assert.Null(parameters.MaxYearOfBirth);
31+
Assert.True(parameters.ValidYearRange);
32+
}
33+
34+
[Fact]
35+
public void GivenOnlyAMinYear_WhenTheRangeIsValidated_ThenItIsAccepted()
36+
{
37+
var parameters = new OwnerParameters { MinYearOfBirth = 1975 };
38+
39+
Assert.True(parameters.ValidYearRange);
40+
}
41+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using Entities.Helpers;
2+
using Entities.Models;
3+
using Repository;
4+
using System;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using Xunit;
8+
9+
namespace AccountOwnerServer.Tests;
10+
11+
/// <summary>
12+
/// These run against a real SQL Server started by Testcontainers. They are skipped unless
13+
/// CODEMAZE_SQLSERVER_TESTS=1 is set, because the SQL Server image is not guaranteed to be
14+
/// available on every machine or CI runner.
15+
/// </summary>
16+
public class OwnerRepositorySqlServerTests
17+
{
18+
[SqlServerFact]
19+
public async Task GivenAPageSizeOfTwo_WhenWeAskForTheSecondPage_ThenWeGetTwoOwnersAndTheRightMetadata()
20+
{
21+
await using var sample = await SqlServerSample.StartAsync();
22+
await using var context = sample.CreateContext();
23+
24+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
25+
26+
var owners = await repository.GetOwners(new OwnerParameters { PageNumber = 2, PageSize = 2 });
27+
28+
Assert.Equal(2, owners.Count);
29+
Assert.Equal(5, owners.TotalCount);
30+
Assert.Equal(3, owners.TotalPages);
31+
Assert.True(owners.HasPrevious);
32+
Assert.True(owners.HasNext);
33+
}
34+
35+
[SqlServerFact]
36+
public async Task GivenTheSameMinAndMaxYear_WhenWeFilter_ThenTheOwnerBornInThatYearComesBack()
37+
{
38+
await using var sample = await SqlServerSample.StartAsync();
39+
await using var context = sample.CreateContext();
40+
41+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
42+
43+
var owners = await repository.GetOwners(new OwnerParameters
44+
{
45+
MinYearOfBirth = 1990,
46+
MaxYearOfBirth = 1990
47+
});
48+
49+
Assert.Equal(1, owners.TotalCount);
50+
Assert.Equal("Sam Query", NameOf(owners.Single()));
51+
}
52+
53+
[SqlServerFact]
54+
public async Task GivenOnlyAMinimumYear_WhenWeFilter_ThenTheUpperBoundIsOpen()
55+
{
56+
await using var sample = await SqlServerSample.StartAsync();
57+
await using var context = sample.CreateContext();
58+
59+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
60+
61+
var owners = await repository.GetOwners(new OwnerParameters { MinYearOfBirth = 1990 });
62+
63+
Assert.Equal(2, owners.TotalCount);
64+
}
65+
66+
[SqlServerFact]
67+
public async Task GivenALowerCaseSearchTerm_WhenWeSearch_ThenTheDefaultCollationStillMatches()
68+
{
69+
await using var sample = await SqlServerSample.StartAsync();
70+
await using var context = sample.CreateContext();
71+
72+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
73+
74+
var owners = await repository.GetOwners(new OwnerParameters { SearchTerm = "anna" });
75+
76+
Assert.Equal(1, owners.TotalCount);
77+
Assert.Equal("Anna Bosh", NameOf(owners.Single()));
78+
}
79+
80+
[SqlServerFact]
81+
public async Task GivenAnUnknownOrderByField_WhenWeQuery_ThenThePageIsStillOrderedRatherThanFailing()
82+
{
83+
await using var sample = await SqlServerSample.StartAsync();
84+
await using var context = sample.CreateContext();
85+
86+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
87+
88+
var owners = await repository.GetOwners(new OwnerParameters { OrderBy = "age" });
89+
90+
Assert.Equal(5, owners.TotalCount);
91+
Assert.Equal("Anna Bosh", NameOf(owners.First()));
92+
}
93+
94+
[SqlServerFact]
95+
public async Task GivenAnUpperCaseDescToken_WhenWeQuery_ThenTheOrderIsDescending()
96+
{
97+
await using var sample = await SqlServerSample.StartAsync();
98+
await using var context = sample.CreateContext();
99+
100+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
101+
102+
var owners = await repository.GetOwners(new OwnerParameters { OrderBy = "name DESC" });
103+
104+
Assert.Equal("Sam Query", NameOf(owners.First()));
105+
}
106+
107+
[SqlServerFact]
108+
public async Task GivenFieldsAndAPageSize_WhenWeQuery_ThenOnlyThePageIsShapedAndTheMetadataComesFromTheQuery()
109+
{
110+
await using var sample = await SqlServerSample.StartAsync();
111+
await using var context = sample.CreateContext();
112+
113+
var repository = new OwnerRepository(context, new SortHelper<Owner>(), new DataShaper<Owner>());
114+
115+
var owners = await repository.GetOwners(new OwnerParameters
116+
{
117+
Fields = "name",
118+
PageSize = 2,
119+
PageNumber = 1
120+
});
121+
122+
Assert.Equal(2, owners.Count);
123+
Assert.Equal(5, owners.TotalCount);
124+
Assert.Equal(3, owners.TotalPages);
125+
}
126+
127+
private static string NameOf(Entity owner) => owner[nameof(Owner.Name)].ToString()!;
128+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Entities.Models;
2+
using Xunit;
3+
4+
namespace AccountOwnerServer.Tests;
5+
6+
public class QueryStringParametersTests
7+
{
8+
[Theory]
9+
[InlineData(0, 1)]
10+
[InlineData(-3, 1)]
11+
[InlineData(2, 2)]
12+
public void GivenAPageNumber_WhenItIsSet_ThenItNeverDropsBelowOne(int requested, int expected)
13+
{
14+
var parameters = new OwnerParameters { PageNumber = requested };
15+
16+
Assert.Equal(expected, parameters.PageNumber);
17+
}
18+
19+
[Theory]
20+
[InlineData(0, 1)]
21+
[InlineData(-10, 1)]
22+
[InlineData(7, 7)]
23+
[InlineData(500, 50)]
24+
public void GivenAPageSize_WhenItIsSet_ThenItIsClampedBetweenOneAndFifty(int requested, int expected)
25+
{
26+
var parameters = new OwnerParameters { PageSize = requested };
27+
28+
Assert.Equal(expected, parameters.PageSize);
29+
}
30+
31+
[Fact]
32+
public void GivenNoQueryString_WhenParametersAreCreated_ThenTheDefaultsAreOneAndTen()
33+
{
34+
var parameters = new OwnerParameters();
35+
36+
Assert.Equal(1, parameters.PageNumber);
37+
Assert.Equal(10, parameters.PageSize);
38+
}
39+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Entities.Models;
2+
using Repository.Extensions;
3+
using System.Linq;
4+
using Xunit;
5+
6+
namespace AccountOwnerServer.Tests;
7+
8+
public class SearchExtensionTests
9+
{
10+
private static IQueryable<Owner> Owners() => SqlServerSample.Owners().AsQueryable();
11+
12+
[Fact]
13+
public void GivenABlankSearchTerm_WhenWeSearch_ThenTheQueryIsReturnedUntouched()
14+
{
15+
var owners = Owners();
16+
17+
Assert.Same(owners, owners.Search(null));
18+
Assert.Same(owners, owners.Search(string.Empty));
19+
Assert.Same(owners, owners.Search(" "));
20+
}
21+
22+
[Fact]
23+
public void GivenANameFragment_WhenWeSearch_ThenTheMatchingOwnerComesBack()
24+
{
25+
var result = Owners().Search("Anna").ToList();
26+
27+
Assert.Single(result);
28+
Assert.Equal("Anna Bosh", result[0].Name);
29+
}
30+
31+
[Fact]
32+
public void GivenAnAddressFragment_WhenWeSearch_ThenTheColumnIsSearchedToo()
33+
{
34+
var result = Owners().Search("Wellfield").ToList();
35+
36+
Assert.Single(result);
37+
Assert.Equal("John Keen", result[0].Name);
38+
}
39+
40+
[Fact]
41+
public void GivenAPaddedSearchTerm_WhenWeSearch_ThenItIsTrimmedBeforeMatching()
42+
{
43+
var result = Owners().Search(" Somion ").ToList();
44+
45+
Assert.Single(result);
46+
Assert.Equal("Nick Somion", result[0].Name);
47+
}
48+
}

0 commit comments

Comments
 (0)