From a5255639533ab805088579be42fc4ac5495f1d81 Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 25 Nov 2024 10:49:13 +0100 Subject: [PATCH] Migrate everything from Shouldly to FluentAssertions (#1262) * Migrate everything from Shouldly to FluentAssertions * Don't reference Testing.csproj from MiniLcm.Tests * Address feedback * Upgrade to FluentAssertions 7-prerelease * Fix assertion that's now case-sensitive --------- Co-authored-by: Robin Munn --- .../FwDataMiniLcmBridge.Tests.csproj | 6 +- .../UpdateComplexFormsTests.cs | 28 ++++----- .../FwLiteProjectSync.Tests/EntrySyncTests.cs | 4 +- .../FwLiteProjectSync.Tests.csproj | 2 +- .../LcmCrdt.Tests/Changes/ComplexFormTests.cs | 14 ++--- .../FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj | 2 +- .../LcmCrdt.Tests/SerializationTests.cs | 2 +- .../FwLite/MiniLcm.Tests/BasicApiTestsBase.cs | 2 +- .../MiniLcm.Tests/CreateEntryTestsBase.cs | 12 ++-- .../FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj | 6 +- .../MiniLcm.Tests/SemanticDomainTestsBase.cs | 8 +-- .../MiniLcm.Tests/WritingSystemIdTests.cs | 8 +-- backend/LexBoxApi/GraphQL/ProjectMutations.cs | 4 +- backend/Testing/ApiTests/ApiTestBase.cs | 13 +++-- backend/Testing/ApiTests/AuthTests.cs | 30 +++++----- backend/Testing/ApiTests/FlexJwtTests.cs | 22 ++++--- .../Testing/ApiTests/GqlMiddlewareTests.cs | 12 ++-- backend/Testing/ApiTests/HeaderTests.cs | 4 +- backend/Testing/ApiTests/InvalidRouteTests.cs | 6 +- .../ApiTests/NewProjectRaceCondition.cs | 15 +++-- .../Testing/ApiTests/OrgPermissionTests.cs | 44 +++++++------- .../ApiTests/ProjectPermissionTests.cs | 16 ++--- .../ApiTests/ResetProjectRaceConditions.cs | 22 +++---- .../Testing/Fixtures/IntegrationFixture.cs | 6 +- .../Fixtures/IntegrationFixtureTests.cs | 8 +-- .../Fixtures/Tests/ServicesFixtureTests.cs | 4 +- .../LexAuthUserOutOfSyncExtensionsTests.cs | 58 +++++++++---------- .../Testing/LexCore/CrdtServerCommitTests.cs | 8 +-- backend/Testing/LexCore/LexAuthUserTests.cs | 52 +++++++++-------- .../Testing/LexCore/PasswordHashingTests.cs | 6 +- backend/Testing/LexCore/ProjectCodeTests.cs | 6 +- .../LexCore/Services/HgServiceTests.cs | 12 ++-- .../LexCore/Services/ProjectServiceTest.cs | 17 +++--- .../Utils/ConcurrentWeakDictionaryTests.cs | 20 +++---- backend/Testing/LexCore/Utils/GqlUtils.cs | 8 +-- .../Services/CleanupResetProjectsTests.cs | 16 ++--- .../IsLanguageForgeProjectDataLoaderTests.cs | 10 ++-- backend/Testing/Services/JwtHelper.cs | 4 +- .../Testing/Services/SendReceiveService.cs | 14 ++--- backend/Testing/Services/Utils.cs | 10 ++-- backend/Testing/Services/UtilsTests.cs | 4 +- .../SyncReverseProxy/LegacyProjectApiTests.cs | 57 +++++++++--------- .../SyncReverseProxy/ProxyHgRequestTests.cs | 20 +++---- .../SyncReverseProxy/ResumableTests.cs | 24 ++++---- .../SendReceiveServiceTests.cs | 51 ++++++++-------- backend/Testing/Testing.csproj | 2 +- backend/Testing/Usings.cs | 2 +- 47 files changed, 352 insertions(+), 349 deletions(-) diff --git a/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj b/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj index 13c53ae52..f2ff05e5d 100644 --- a/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj +++ b/backend/FwLite/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj @@ -20,14 +20,14 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/backend/FwLite/FwDataMiniLcmBridge.Tests/UpdateComplexFormsTests.cs b/backend/FwLite/FwDataMiniLcmBridge.Tests/UpdateComplexFormsTests.cs index 7499f06e3..acc4c96bf 100644 --- a/backend/FwLite/FwDataMiniLcmBridge.Tests/UpdateComplexFormsTests.cs +++ b/backend/FwLite/FwDataMiniLcmBridge.Tests/UpdateComplexFormsTests.cs @@ -34,7 +34,7 @@ await _api.UpdateEntry(complexForm.Id, ComplexFormComponent.FromEntries(complexForm, component))); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.Components.Should() + entry.Components.Should() .ContainSingle(c => c.ComponentEntryId == component.Id && c.ComplexFormEntryId == complexForm.Id); } @@ -63,7 +63,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Remove(e => e.Components, 0)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.Components.Should().BeEmpty(); + entry.Components.Should().BeEmpty(); } [Fact] @@ -92,7 +92,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Set(e => e.Components[0].ComponentEntryId, component2.Id)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.Components.Should().ContainSingle().Subject; + var complexFormComponent = entry.Components.Should().ContainSingle().Subject; complexFormComponent.ComponentEntryId.Should().Be(component2.Id); } @@ -127,7 +127,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Set(e => e.Components[0].ComponentSenseId, component2SenseId)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.Components.Should().ContainSingle().Subject; + var complexFormComponent = entry.Components.Should().ContainSingle().Subject; complexFormComponent.ComponentEntryId.Should().Be(component2.Id); complexFormComponent.ComponentSenseId.Should().Be(component2SenseId); } @@ -163,7 +163,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Set(e => e.Components[0].ComponentSenseId, null)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.Components.Should() + entry.Components.Should() .ContainSingle(c => c.ComponentEntryId == component2.Id && c.ComponentSenseId == null); } @@ -193,7 +193,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Set(e => e.Components[0].ComplexFormEntryId, complexForm2.Id)); var entry = await _api.GetEntry(complexForm2.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.Components.Should().ContainSingle().Subject; + var complexFormComponent = entry.Components.Should().ContainSingle().Subject; complexFormComponent.ComponentEntryId.Should().Be(component1.Id); } @@ -208,7 +208,7 @@ await _api.UpdateEntry(component.Id, ComplexFormComponent.FromEntries(complexForm, component))); var entry = await _api.GetEntry(component.Id); entry.Should().NotBeNull(); - entry!.ComplexForms.Should() + entry.ComplexForms.Should() .ContainSingle(c => c.ComponentEntryId == component.Id && c.ComplexFormEntryId == complexForm.Id); } @@ -237,7 +237,7 @@ await _api.UpdateEntry(component.Id, new UpdateObjectInput().Remove(e => e.ComplexForms, 0)); var entry = await _api.GetEntry(component.Id); entry.Should().NotBeNull(); - entry!.ComplexForms.Should().BeEmpty(); + entry.ComplexForms.Should().BeEmpty(); } [Fact] @@ -266,7 +266,7 @@ await _api.UpdateEntry(component1.Id, new UpdateObjectInput().Set(e => e.ComplexForms[0].ComplexFormEntryId, complexForm2.Id)); var entry = await _api.GetEntry(component1.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.ComplexForms.Should().ContainSingle().Subject; + var complexFormComponent = entry.ComplexForms.Should().ContainSingle().Subject; complexFormComponent.ComplexFormEntryId.Should().Be(complexForm2.Id); } @@ -296,7 +296,7 @@ await _api.UpdateEntry(component1.Id, new UpdateObjectInput().Set(e => e.ComplexForms[0].ComponentEntryId, component2.Id)); var entry = await _api.GetEntry(component2.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.ComplexForms.Should().ContainSingle().Subject; + var complexFormComponent = entry.ComplexForms.Should().ContainSingle().Subject; complexFormComponent.ComponentEntryId.Should().Be(component2.Id); complexFormComponent.ComplexFormEntryId.Should().Be(complexFormId); } @@ -338,7 +338,7 @@ await _api.UpdateEntry(component1.Id, new UpdateObjectInput().Set(e => e.ComplexForms[0].ComponentSenseId, component1SenseId2)); var entry = await _api.GetEntry(component1.Id); entry.Should().NotBeNull(); - var complexFormComponent = entry!.ComplexForms.Should().ContainSingle().Subject; + var complexFormComponent = entry.ComplexForms.Should().ContainSingle().Subject; complexFormComponent.ComponentEntryId.Should().Be(componentId1); complexFormComponent.ComponentSenseId.Should().Be(component1SenseId2); } @@ -353,7 +353,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Add(e => e.ComplexFormTypes, complexFormType)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.ComplexFormTypes.Should().ContainSingle(c => c.Id == complexFormType.Id); + entry.ComplexFormTypes.Should().ContainSingle(c => c.Id == complexFormType.Id); } [Fact] @@ -369,7 +369,7 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Remove(e => e.ComplexFormTypes, 0)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.ComplexFormTypes.Should().BeEmpty(); + entry.ComplexFormTypes.Should().BeEmpty(); } [Fact] @@ -382,6 +382,6 @@ await _api.UpdateEntry(complexForm.Id, new UpdateObjectInput().Set(e => e.ComplexFormTypes[0].Id, complexFormType2.Id)); var entry = await _api.GetEntry(complexForm.Id); entry.Should().NotBeNull(); - entry!.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(complexFormType2.Id); + entry.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(complexFormType2.Id); } } diff --git a/backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs b/backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs index d1b264839..021587cfd 100644 --- a/backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs +++ b/backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs @@ -1,7 +1,7 @@ -using FluentAssertions.Equivalency; -using FwLiteProjectSync.Tests.Fixtures; +using FwLiteProjectSync.Tests.Fixtures; using MiniLcm.Models; using MiniLcm.SyncHelpers; +using MiniLcm.Tests; using MiniLcm.Tests.AutoFakerHelpers; using Soenneker.Utils.AutoBogus; diff --git a/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj b/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj index 1ae1063f4..c988caadc 100644 --- a/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj +++ b/backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/backend/FwLite/LcmCrdt.Tests/Changes/ComplexFormTests.cs b/backend/FwLite/LcmCrdt.Tests/Changes/ComplexFormTests.cs index 5f5be9ed1..804cacdad 100644 --- a/backend/FwLite/LcmCrdt.Tests/Changes/ComplexFormTests.cs +++ b/backend/FwLite/LcmCrdt.Tests/Changes/ComplexFormTests.cs @@ -18,7 +18,7 @@ public async Task AddComplexFormType() await fixture.DataModel.AddChange(Guid.NewGuid(), change); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - complexEntry!.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(change.ComplexFormType.Id); + complexEntry.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(change.ComplexFormType.Id); } [Fact] @@ -33,14 +33,14 @@ await fixture.DataModel.AddChange( ); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - complexEntry!.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(complexFormType.Id); + complexEntry.ComplexFormTypes.Should().ContainSingle().Which.Id.Should().Be(complexFormType.Id); await fixture.DataModel.AddChange( Guid.NewGuid(), new RemoveComplexFormTypeChange(complexEntry.Id, complexFormType.Id) ); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - complexEntry!.ComplexFormTypes.Should().BeEmpty(); + complexEntry.ComplexFormTypes.Should().BeEmpty(); } [Fact] @@ -55,12 +55,12 @@ public async Task AddEntryComponent() await fixture.DataModel.AddChange(Guid.NewGuid(), new AddEntryComponentChange(ComplexFormComponent.FromEntries(complexEntry, rackEntry))); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - complexEntry!.Components.Should().ContainSingle(e => e.ComponentEntryId == coatEntry.Id); + complexEntry.Components.Should().ContainSingle(e => e.ComponentEntryId == coatEntry.Id); complexEntry.Components.Should().ContainSingle(e => e.ComponentEntryId == rackEntry.Id); coatEntry = await fixture.Api.GetEntry(coatEntry.Id); coatEntry.Should().NotBeNull(); - coatEntry!.ComplexForms.Should().ContainSingle(e => e.ComplexFormEntryId == complexEntry.Id); + coatEntry.ComplexForms.Should().ContainSingle(e => e.ComplexFormEntryId == complexEntry.Id); } [Fact] @@ -74,11 +74,11 @@ public async Task DeleteEntryComponent() await fixture.DataModel.AddChange(Guid.NewGuid(), new AddEntryComponentChange(ComplexFormComponent.FromEntries(complexEntry, rackEntry))); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - var component = complexEntry!.Components.First(); + var component = complexEntry.Components.First(); await fixture.DataModel.AddChange(Guid.NewGuid(), new DeleteChange(component.Id)); complexEntry = await fixture.Api.GetEntry(complexEntry.Id); complexEntry.Should().NotBeNull(); - complexEntry!.Components.Should().NotContain(c => c.Id == component.Id); + complexEntry.Components.Should().NotContain(c => c.Id == component.Id); } } diff --git a/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj b/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj index d955b734a..9f03df743 100644 --- a/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj +++ b/backend/FwLite/LcmCrdt.Tests/LcmCrdt.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/backend/FwLite/LcmCrdt.Tests/SerializationTests.cs b/backend/FwLite/LcmCrdt.Tests/SerializationTests.cs index 268255141..52002507f 100644 --- a/backend/FwLite/LcmCrdt.Tests/SerializationTests.cs +++ b/backend/FwLite/LcmCrdt.Tests/SerializationTests.cs @@ -76,7 +76,7 @@ public void CanDeserializeMultiString() }; var actualMs = JsonSerializer.Deserialize(json); actualMs.Should().NotBeNull(); - actualMs!.Values.Should().ContainKey("en"); + actualMs.Values.Should().ContainKey("en"); actualMs.Should().BeEquivalentTo(expectedMs); } diff --git a/backend/FwLite/MiniLcm.Tests/BasicApiTestsBase.cs b/backend/FwLite/MiniLcm.Tests/BasicApiTestsBase.cs index da63a7f4d..9b1f05144 100644 --- a/backend/FwLite/MiniLcm.Tests/BasicApiTestsBase.cs +++ b/backend/FwLite/MiniLcm.Tests/BasicApiTestsBase.cs @@ -202,7 +202,7 @@ public async Task GetEntry() { var entry = await Api.GetEntry(Entry1Id); entry.Should().NotBeNull(); - entry!.LexemeForm.Values.Should().NotBeEmpty(); + entry.LexemeForm.Values.Should().NotBeEmpty(); var sense = entry.Senses.Should() .NotBeEmpty($"because '{entry.LexemeForm.Values.First().Value}' should have a sense").And.Subject.First(); sense.Gloss.Values.Should().NotBeEmpty(); diff --git a/backend/FwLite/MiniLcm.Tests/CreateEntryTestsBase.cs b/backend/FwLite/MiniLcm.Tests/CreateEntryTestsBase.cs index 477362c03..37fef2f21 100644 --- a/backend/FwLite/MiniLcm.Tests/CreateEntryTestsBase.cs +++ b/backend/FwLite/MiniLcm.Tests/CreateEntryTestsBase.cs @@ -9,7 +9,7 @@ public async Task CanCreateEntry() { var entry = await Api.CreateEntry(new() { LexemeForm = { { "en", "test" } } }); entry.Should().NotBeNull(); - entry!.LexemeForm.Values.Should().ContainKey("en"); + entry.LexemeForm.Values.Should().ContainKey("en"); entry.LexemeForm.Values["en"].Should().Be("test"); } @@ -53,7 +53,7 @@ public async Task CanCreate_WithComponentsProperty() }); entry = await Api.GetEntry(entry.Id); entry.Should().NotBeNull(); - entry!.Components.Should().ContainSingle(c => c.ComponentEntryId == component.Id); + entry.Components.Should().ContainSingle(c => c.ComponentEntryId == component.Id); } [Fact] @@ -78,7 +78,7 @@ public async Task CanCreate_WithComplexFormsProperty() }); entry = await Api.GetEntry(entry.Id); entry.Should().NotBeNull(); - entry!.ComplexForms.Should().ContainSingle(c => c.ComplexFormEntryId == complexForm.Id); + entry.ComplexForms.Should().ContainSingle(c => c.ComplexFormEntryId == complexForm.Id); } [Fact] @@ -110,11 +110,11 @@ await Api.CreateEntry(new() var entry = await Api.GetEntry(component.Id); entry.Should().NotBeNull(); - entry!.ComplexForms.Should().ContainSingle().Which.ComponentSenseId.Should().Be(componentSenseId); + entry.ComplexForms.Should().ContainSingle().Which.ComponentSenseId.Should().Be(componentSenseId); entry = await Api.GetEntry(complexFormEntryId); entry.Should().NotBeNull(); - entry!.Components.Should().ContainSingle(c => + entry.Components.Should().ContainSingle(c => c.ComplexFormEntryId == complexFormEntryId && c.ComponentEntryId == component.Id && c.ComponentSenseId == componentSenseId); } @@ -133,6 +133,6 @@ public async Task CanCreate_WithComplexFormTypesProperty() }); entry = await Api.GetEntry(entry.Id); entry.Should().NotBeNull(); - entry!.ComplexFormTypes.Should().ContainSingle(c => c.Id == complexFormType.Id); + entry.ComplexFormTypes.Should().ContainSingle(c => c.Id == complexFormType.Id); } } diff --git a/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj b/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj index 83030857f..be07e4f4e 100644 --- a/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj +++ b/backend/FwLite/MiniLcm.Tests/MiniLcm.Tests.csproj @@ -12,14 +12,14 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/backend/FwLite/MiniLcm.Tests/SemanticDomainTestsBase.cs b/backend/FwLite/MiniLcm.Tests/SemanticDomainTestsBase.cs index 6704a50f0..38b6a5f63 100644 --- a/backend/FwLite/MiniLcm.Tests/SemanticDomainTestsBase.cs +++ b/backend/FwLite/MiniLcm.Tests/SemanticDomainTestsBase.cs @@ -31,11 +31,11 @@ await Api.CreateEntry(new Entry() }); } - private Task GetEntry() + private async Task GetEntry() { - var entry = Api.GetEntry(_entryId); + var entry = await Api.GetEntry(_entryId); entry.Should().NotBeNull(); - return entry!; + return entry; } [Fact] @@ -55,7 +55,7 @@ public async Task Sense_HasSemanticDomains() { var entry = await GetEntry(); entry.Should().NotBeNull(); - var sense = entry!.Senses.First(s => s.SemanticDomains.Any()); + var sense = entry.Senses.First(s => s.SemanticDomains.Any()); sense.SemanticDomains.Should().NotBeEmpty(); sense.SemanticDomains.Should().AllSatisfy(sd => { diff --git a/backend/FwLite/MiniLcm.Tests/WritingSystemIdTests.cs b/backend/FwLite/MiniLcm.Tests/WritingSystemIdTests.cs index 6448f77b0..14290cc07 100644 --- a/backend/FwLite/MiniLcm.Tests/WritingSystemIdTests.cs +++ b/backend/FwLite/MiniLcm.Tests/WritingSystemIdTests.cs @@ -1,6 +1,4 @@ -using MiniLcm.Models; - -namespace MiniLcm.Tests; +namespace MiniLcm.Tests; public class WritingSystemIdTests { @@ -11,7 +9,7 @@ public class WritingSystemIdTests public void ValidWritingSystemId_ShouldNotThrow(string code) { var ws = new WritingSystemId(code); - ws.Should().NotBeNull(); + ws.Should().NotBe(default); } [Theory] @@ -29,6 +27,6 @@ public void InvalidWritingSystemId_ShouldThrow(string code) public void DefaultWritingSystemId_IsValid() { var ws = new WritingSystemId("default"); - ws.Should().NotBeNull(); + ws.Should().NotBe(default); } } diff --git a/backend/LexBoxApi/GraphQL/ProjectMutations.cs b/backend/LexBoxApi/GraphQL/ProjectMutations.cs index 2f6df4039..b481eb7c6 100644 --- a/backend/LexBoxApi/GraphQL/ProjectMutations.cs +++ b/backend/LexBoxApi/GraphQL/ProjectMutations.cs @@ -26,14 +26,14 @@ public enum CreateProjectResult Requested } - public record CreateProjectResponse(Guid? Id, CreateProjectResult Result); + public record CreateProjectResponse(Guid Id, CreateProjectResult Result); [Error] [Error] [Error] [UseMutationConvention] [RefreshJwt] [VerifiedEmailRequired] - public async Task CreateProject( + public async Task CreateProject( LoggedInContext loggedInContext, IPermissionService permissionService, CreateProjectInput input, diff --git a/backend/Testing/ApiTests/ApiTestBase.cs b/backend/Testing/ApiTests/ApiTestBase.cs index 1f9901865..cbf22d856 100644 --- a/backend/Testing/ApiTests/ApiTestBase.cs +++ b/backend/Testing/ApiTests/ApiTestBase.cs @@ -1,10 +1,10 @@ using System.Diagnostics.CodeAnalysis; using System.Net.Http.Json; using System.Text.Json.Nodes; +using FluentAssertions; using LexCore.Auth; using Microsoft.Extensions.Http.Resilience; using Polly; -using Shouldly; using Testing.LexCore.Utils; using Testing.Services; @@ -67,14 +67,14 @@ public async Task ExecuteGql([StringSyntax("graphql")] string gql, b var response = await HttpClient.PostAsJsonAsync($"{BaseUrl}/api/graphql{jwtParam}", new { query = gql }); if (JwtHelper.TryGetJwtFromLoginResponse(response, out var jwt)) CurrJwt = jwt; var jsonResponse = await response.Content.ReadFromJsonAsync(); - jsonResponse.ShouldNotBeNull($"for query {gql} ({(int)response.StatusCode} ({response.ReasonPhrase}))"); + jsonResponse.Should().NotBeNull($"for query {gql} ({(int)response.StatusCode} ({response.ReasonPhrase}))"); GqlUtils.ValidateGqlErrors(jsonResponse, expectGqlError); if (expectSuccessCode) - response.IsSuccessStatusCode.ShouldBeTrue($"code was {(int)response.StatusCode} ({response.ReasonPhrase})"); + response.IsSuccessStatusCode.Should().BeTrue($"code was {(int)response.StatusCode} ({response.ReasonPhrase})"); return jsonResponse; } - public async Task GetProjectLastCommit(string projectCode) + public async Task GetProjectLastCommit(string projectCode) { var jsonResult = await ExecuteGql($$""" query projectLastCommit { @@ -83,8 +83,9 @@ query projectLastCommit { } } """); - var project = jsonResult?["data"]?["projectByCode"].ShouldBeOfType(); - return project?["lastCommit"]?.ToString(); + var project = jsonResult?["data"]?["projectByCode"].Should().BeOfType().Subject; + var stringDate = project?["lastCommit"]?.ToString(); + return stringDate == null ? null : DateTimeOffset.Parse(stringDate); } public async Task StartLexboxProjectReset(string projectCode) diff --git a/backend/Testing/ApiTests/AuthTests.cs b/backend/Testing/ApiTests/AuthTests.cs index 36fa74ae5..33a065e4f 100644 --- a/backend/Testing/ApiTests/AuthTests.cs +++ b/backend/Testing/ApiTests/AuthTests.cs @@ -7,7 +7,7 @@ using LexCore.Auth; using LexSyncReverseProxy; using LfClassicData; -using Shouldly; +using FluentAssertions; using Testing.Services; namespace Testing.ApiTests; @@ -22,16 +22,16 @@ public async Task TestLoginAndVerifyDifferentUsers() var managerResponse = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"{BaseUrl}/api/user/currentUser"), HttpCompletionOption.ResponseContentRead); - managerResponse.StatusCode.ShouldBe(HttpStatusCode.OK); + managerResponse.StatusCode.Should().Be(HttpStatusCode.OK); var manager = await managerResponse.Content.ReadFromJsonAsync(); - manager.GetProperty("email").GetString().ShouldBe("manager@test.com"); + manager.GetProperty("email").GetString().Should().Be("manager@test.com"); await LoginAs("admin", TestingEnvironmentVariables.DefaultPassword); var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"{BaseUrl}/api/user/currentUser"), HttpCompletionOption.ResponseContentRead); var admin = await response.Content.ReadFromJsonAsync(); - admin.GetProperty("email").GetString().ShouldBe("admin@test.com"); + admin.GetProperty("email").GetString().Should().Be("admin@test.com"); } [Fact] @@ -41,20 +41,20 @@ public async Task TestGqlVerifyDifferentUsers() var query = """query testGetMe { meAuth { id email }}"""; await LoginAs("manager", TestingEnvironmentVariables.DefaultPassword); var manager = await ExecuteGql(query); - manager.ShouldNotBeNull(); - manager["data"]!["meAuth"]!["email"]!.ToString().ShouldBe("manager@test.com"); + manager.Should().NotBeNull(); + manager["data"]!["meAuth"]!["email"]!.ToString().Should().Be("manager@test.com"); await LoginAs("admin", TestingEnvironmentVariables.DefaultPassword); var admin = await ExecuteGql(query); - admin.ShouldNotBeNull(); - admin["data"]!["meAuth"]!["email"]!.ToString().ShouldBe("admin@test.com"); + admin.Should().NotBeNull(); + admin["data"]!["meAuth"]!["email"]!.ToString().Should().Be("admin@test.com"); } [Fact] public async Task NotLoggedInIsNotPermittedToCallRequiresAuthApi() { var response = await HttpClient.GetAsync($"{BaseUrl}/api/AuthTesting/requires-auth"); - response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + response.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } [Fact] @@ -70,7 +70,7 @@ public async Task ManagerIsForbiddenFromAdminApi() { await LoginAs("manager", TestingEnvironmentVariables.DefaultPassword); var response = await HttpClient.GetAsync($"{BaseUrl}/api/AuthTesting/requires-admin"); - response.StatusCode.ShouldBe(HttpStatusCode.Forbidden); + response.StatusCode.Should().Be(HttpStatusCode.Forbidden); } [Fact] @@ -86,11 +86,11 @@ public async Task NoOneCanCallForgotPasswordApi() { await LoginAs("manager", TestingEnvironmentVariables.DefaultPassword); var response = await HttpClient.GetAsync($"{BaseUrl}/api/AuthTesting/requires-forgot-password"); - response.StatusCode.ShouldBe(HttpStatusCode.Forbidden); + response.StatusCode.Should().Be(HttpStatusCode.Forbidden); await LoginAs("admin", TestingEnvironmentVariables.DefaultPassword); response = await HttpClient.GetAsync($"{BaseUrl}/api/AuthTesting/requires-forgot-password"); - response.StatusCode.ShouldBe(HttpStatusCode.Forbidden); + response.StatusCode.Should().Be(HttpStatusCode.Forbidden); } [Fact] @@ -99,7 +99,7 @@ public async Task ClearingCookiesWorks() await LoginAs("manager", TestingEnvironmentVariables.DefaultPassword); ClearCookies(); var response = await HttpClient.GetAsync($"{BaseUrl}/api/AuthTesting/requires-auth"); - response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + response.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } [Fact(Skip = "Not working due to oauth, to solve we should setup a login via oauth to use the right jwt")] @@ -136,7 +136,7 @@ public async Task JwtWithInvalidSignatureFailsAuth() { Headers = { Authorization = new AuthenticationHeaderValue("Bearer", newJwt) } }); - response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + response.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } //these must match because auth determines the project code from the route key using the method in HgHelpers @@ -144,6 +144,6 @@ public async Task JwtWithInvalidSignatureFailsAuth() [Fact] public void RouteKeyInLfClassicRoutesMustMatchRouteKeyInProxyConstants() { - LfClassicRoutes.ProjectCodeRouteKey.ShouldBe(ProxyConstants.HgProjectCodeRouteKey); + LfClassicRoutes.ProjectCodeRouteKey.Should().Be(ProxyConstants.HgProjectCodeRouteKey); } } diff --git a/backend/Testing/ApiTests/FlexJwtTests.cs b/backend/Testing/ApiTests/FlexJwtTests.cs index 4594590a1..3f3c82108 100644 --- a/backend/Testing/ApiTests/FlexJwtTests.cs +++ b/backend/Testing/ApiTests/FlexJwtTests.cs @@ -1,9 +1,7 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Net.Http.Json; -using System.Security.Claims; +using System.Net.Http.Json; using System.Text.Json; using LexCore.Auth; -using Shouldly; +using FluentAssertions; using Testing.Services; namespace Testing.ApiTests; @@ -37,18 +35,18 @@ public async Task CanGetProjectSpecificToken() //intentionally not using the RefreshResponse class to make sure this test still fails if properties are renamed var json = await response.Content.ReadFromJsonAsync(); var projectToken = json.GetProperty("projectToken").GetString(); - projectToken.ShouldNotBeEmpty(); + projectToken.Should().NotBeNullOrEmpty(); var user = ParseUserToken(projectToken); - user.Projects.ShouldHaveSingleItem(); - user.Audience.ShouldBe(LexboxAudience.SendAndReceive); + user.Projects.Should().ContainSingle(); + user.Audience.Should().Be(LexboxAudience.SendAndReceive); var flexToken = json.GetProperty("flexToken").GetString(); - flexToken.ShouldNotBeEmpty(); + flexToken.Should().NotBeNullOrEmpty(); var flexUser = ParseUserToken(flexToken); - flexUser.Projects.ShouldBeEmpty(); - flexUser.Audience.ShouldBe(LexboxAudience.SendAndReceiveRefresh); + flexUser.Projects.Should().BeEmpty(); + flexUser.Audience.Should().Be(LexboxAudience.SendAndReceiveRefresh); - json.GetProperty("projectTokenExpiresAt").GetDateTime().ShouldNotBe(default); - json.GetProperty("flexTokenExpiresAt").GetDateTime().ShouldNotBe(default); + json.GetProperty("projectTokenExpiresAt").GetDateTime().Should().NotBe(default); + json.GetProperty("flexTokenExpiresAt").GetDateTime().Should().NotBe(default); } } diff --git a/backend/Testing/ApiTests/GqlMiddlewareTests.cs b/backend/Testing/ApiTests/GqlMiddlewareTests.cs index d6c0ed834..72074b694 100644 --- a/backend/Testing/ApiTests/GqlMiddlewareTests.cs +++ b/backend/Testing/ApiTests/GqlMiddlewareTests.cs @@ -1,6 +1,6 @@ using System.Text.Json.Nodes; using LexCore.Entities; -using Shouldly; +using FluentAssertions; using Testing.Fixtures; using static Testing.Services.Utils; @@ -80,11 +80,11 @@ await Task.WhenAll( // if the user is allowed to view all members var json = await QueryMyProjectsWithMembers(); - json.ShouldNotBeNull(); + json.Should().NotBeNull(); var myProjects = json["data"]!["myProjects"]!.AsArray(); var ids = myProjects.Select(p => p!["id"]!.GetValue()); - projects.Select(p => p.Id).ShouldBeSubsetOf(ids); + projects.Select(p => p.Id).Should().BeSubsetOf(ids); } [Fact] @@ -104,7 +104,7 @@ await _adminApiTester.ExecuteGql($$""" } } """, expectGqlError: true); // we're not a member yet - _adminApiTester.CurrJwt.ShouldBe(editorJwt); // token wasn't updated + _adminApiTester.CurrJwt.Should().Be(editorJwt); // token wasn't updated await AddMemberToProject(config, _adminApiTester, "editor", ProjectRole.Editor, _adminJwt); @@ -116,7 +116,7 @@ await _adminApiTester.ExecuteGql($$""" } } """, expectGqlError: true); // we're a member, but didn't query for users, so... - _adminApiTester.CurrJwt.ShouldBe(editorJwt); // token wasn't updated + _adminApiTester.CurrJwt.Should().Be(editorJwt); // token wasn't updated var response = await _adminApiTester.ExecuteGql($$""" query { @@ -129,6 +129,6 @@ await _adminApiTester.ExecuteGql($$""" } } """, expectGqlError: false); // we queried for users, so... - _adminApiTester.CurrJwt.ShouldNotBe(editorJwt); // token was updated + _adminApiTester.CurrJwt.Should().NotBe(editorJwt); // token was updated } } diff --git a/backend/Testing/ApiTests/HeaderTests.cs b/backend/Testing/ApiTests/HeaderTests.cs index 8c3bf2bfc..97648256e 100644 --- a/backend/Testing/ApiTests/HeaderTests.cs +++ b/backend/Testing/ApiTests/HeaderTests.cs @@ -1,5 +1,5 @@ using System.Net; -using Shouldly; +using FluentAssertions; namespace Testing.ApiTests; @@ -31,7 +31,7 @@ public async Task CheckCloudflareHeaderSizeLimit() if (response.StatusCode != HttpStatusCode.OK) failStatusCodes.Add(response.StatusCode); } - failStatusCodes.ShouldBeEmpty(); + failStatusCodes.Should().BeEmpty(); } private string RandomString(int length) diff --git a/backend/Testing/ApiTests/InvalidRouteTests.cs b/backend/Testing/ApiTests/InvalidRouteTests.cs index 6886ca88b..9894056d3 100644 --- a/backend/Testing/ApiTests/InvalidRouteTests.cs +++ b/backend/Testing/ApiTests/InvalidRouteTests.cs @@ -1,5 +1,5 @@ using System.Net; -using Shouldly; +using FluentAssertions; using Testing.Services; namespace Testing.ApiTests; @@ -11,13 +11,13 @@ public class InvalidRouteTests : ApiTestBase public async Task ApiPathRequestsShouldBeServedByDotnetForAnonymous() { var response = await HttpClient.GetAsync($"{BaseUrl}/api/login/not-exists"); - response.StatusCode.ShouldBe(HttpStatusCode.NotFound); + response.StatusCode.Should().Be(HttpStatusCode.NotFound); } [Fact] public async Task ApiBasePathRequestsShouldBeServedByDotnetForAuthenticated() { await LoginAs("manager", TestingEnvironmentVariables.DefaultPassword); var response = await HttpClient.GetAsync($"{BaseUrl}/api/login/not-exists"); - response.StatusCode.ShouldBe(HttpStatusCode.NotFound); + response.StatusCode.Should().Be(HttpStatusCode.NotFound); } } diff --git a/backend/Testing/ApiTests/NewProjectRaceCondition.cs b/backend/Testing/ApiTests/NewProjectRaceCondition.cs index 2eed7b63b..6dcd30899 100644 --- a/backend/Testing/ApiTests/NewProjectRaceCondition.cs +++ b/backend/Testing/ApiTests/NewProjectRaceCondition.cs @@ -1,5 +1,5 @@ using System.Text.Json.Nodes; -using Shouldly; +using FluentAssertions; using Testing.Services; namespace Testing.ApiTests; @@ -47,12 +47,17 @@ private async Task CreateQueryAndVerifyProject(Guid id) createProjectResponse { id } + errors { + ... on Error { + message + } + } } } """); - var project = response["data"]!["createProject"]!["createProjectResponse"].ShouldBeOfType(); - project["id"]!.GetValue().ShouldBe(id.ToString()); + var project = response["data"]!["createProject"]!["createProjectResponse"].Should().BeOfType().Subject; + project["id"]!.GetValue().Should().Be(id.ToString()); // Query a 2nd time to ensure the instability of new repos isn't causing trouble response = await ExecuteGql($$""" @@ -66,7 +71,7 @@ private async Task CreateQueryAndVerifyProject(Guid id) } """); - project = response["data"]!["projectByCode"].ShouldBeOfType(); - project["name"]!.GetValue().ShouldBe(name); + project = response["data"]!["projectByCode"].Should().BeOfType().Subject; + project["name"]!.GetValue().Should().Be(name); } } diff --git a/backend/Testing/ApiTests/OrgPermissionTests.cs b/backend/Testing/ApiTests/OrgPermissionTests.cs index fabeab52a..dc8b59873 100644 --- a/backend/Testing/ApiTests/OrgPermissionTests.cs +++ b/backend/Testing/ApiTests/OrgPermissionTests.cs @@ -1,6 +1,6 @@ using System.Text.Json.Nodes; using LexData; -using Shouldly; +using FluentAssertions; namespace Testing.ApiTests; @@ -37,42 +37,42 @@ private async Task QueryOrg(Guid orgId) private static JsonObject GetOrg(JsonObject json) { var org = json["data"]?["orgById"]?.AsObject(); - org.ShouldNotBeNull(); + org.Should().NotBeNull(); return org; } private void MustHaveOneMemberWithEmail(JsonNode org) { org["members"]!.AsArray().Where(m => m?["user"]?["email"]?.GetValue() is { Length: > 0 }) - .ShouldNotBeEmpty(); + .Should().NotBeNullOrEmpty(); } private void MustNotHaveMemberWithEmail(JsonNode org) { org["members"]!.AsArray().Where(m => m?["user"]?["email"]?.GetValue() is { Length: > 0 }) - .ShouldBeEmpty(); + .Should().BeEmpty(); } private void MustHaveOneMemberWithUsername(JsonNode org) { org["members"]!.AsArray().Where(m => m?["user"]?["username"]?.GetValue() is { Length: > 0 }) - .ShouldNotBeEmpty(); + .Should().NotBeNullOrEmpty(); } private void MustNotHaveMemberWithUsername(JsonNode org) { org["members"]!.AsArray().Where(m => m?["user"]?["username"]?.GetValue() is { Length: > 0 }) - .ShouldBeEmpty(); + .Should().BeEmpty(); } private void MustHaveUserNames(JsonNode org) { org["members"]!.AsArray() .Where(m => m?["user"]?["name"]?.GetValue() is { Length: > 0 }) - .ShouldNotBeEmpty(); + .Should().NotBeNullOrEmpty(); } private void MustContainUser(JsonNode org, Guid id) { - org["members"]!.AsArray().ShouldContain( + org["members"]!.AsArray().Should().Contain( m => m!["user"]!["id"]!.GetValue() == id, $"org: '{org["name"]}' members were: {org["members"]!.ToJsonString()}"); } @@ -81,14 +81,14 @@ private void MustHaveOnlyManagers(JsonNode org) { org["members"]!.AsArray() .Where(m => m?["role"]?.GetValue() is not "ADMIN") - .ShouldBeEmpty(); + .Should().BeEmpty(); } private void MustHaveNonManagers(JsonNode org) { org["members"]!.AsArray() .Where(m => m?["role"]?.GetValue() is not "ADMIN") - .ShouldNotBeEmpty(); + .Should().NotBeNullOrEmpty(); } [Fact] @@ -113,8 +113,8 @@ public async Task CanNotListOrgsAndListOrgUsers() """, true, false); var error = json["errors"]?.AsArray().First()?.AsObject(); - error.ShouldNotBeNull(); - error["extensions"]?["code"]?.GetValue().ShouldBe("AUTH_NOT_AUTHORIZED"); + error.Should().NotBeNull(); + error["extensions"]?["code"]?.GetValue().Should().Be("AUTH_NOT_AUTHORIZED"); } [Fact] @@ -134,8 +134,8 @@ public async Task CanNotListOrgsAndListOrgProjects() """, true, false); var error = json["errors"]?.AsArray().First()?.AsObject(); - error.ShouldNotBeNull(); - error["extensions"]?["code"]?.GetValue().ShouldBe("AUTH_NOT_AUTHORIZED"); + error.Should().NotBeNull(); + error["extensions"]?["code"]?.GetValue().Should().Be("AUTH_NOT_AUTHORIZED"); } [Fact] @@ -167,7 +167,7 @@ public async Task OrgMemberCanSeeThemselvesInOrg() { await LoginAs("editor"); var org = GetOrg(await QueryOrg(SeedingData.TestOrgId)); - org.ShouldNotBeNull(); + org.Should().NotBeNull(); MustContainUser(org, SeedingData.EditorId); } @@ -176,7 +176,7 @@ public async Task OrgMemberCanNotSeeMemberEmails() { await LoginAs("editor"); var org = GetOrg(await QueryOrg(SeedingData.TestOrgId)); - org.ShouldNotBeNull(); + org.Should().NotBeNull(); MustHaveUserNames(org); MustNotHaveMemberWithEmail(org); } @@ -186,7 +186,7 @@ public async Task OrgMemberCanNotSeeMemberUsernames() { await LoginAs("editor"); var org = GetOrg(await QueryOrg(SeedingData.TestOrgId)); - org.ShouldNotBeNull(); + org.Should().NotBeNull(); MustHaveUserNames(org); MustNotHaveMemberWithUsername(org); } @@ -203,24 +203,24 @@ public async Task NonMemberCanOnlyQueryManagers() private void MustNotShowConfidentialProjects(JsonNode org) { var projects = org["projects"]!.AsArray(); - projects.ShouldNotBeEmpty(); + projects.Should().NotBeNullOrEmpty(); projects .Where(p => p?["isConfidential"]?.GetValue() != false) - .ShouldBeEmpty(); + .Should().BeEmpty(); } private void MustContainProject(JsonNode org, Guid projectId) { var projects = org["projects"]!.AsArray(); - projects.ShouldNotBeEmpty(); - projects.ShouldContain(p => p!["id"]!.GetValue() == projectId, $"project id '{projectId}' should exist in: {projects.ToJsonString()}"); + projects.Should().NotBeNullOrEmpty(); + projects.Should().Contain(p => p!["id"]!.GetValue() == projectId, $"project id '{projectId}' should exist in: {projects.ToJsonString()}"); } private void MustNotContainProject(JsonNode org, Guid projectId) { var projects = org["projects"]!.AsArray(); if ((projects?.Count ?? 0) == 0) return; - projects!.ShouldNotContain(p => p!["id"]!.GetValue() == projectId, $"project id '{projectId}' should not exist in: {projects!.ToJsonString()}"); + projects!.Should().NotContain(p => p!["id"]!.GetValue() == projectId, $"project id '{projectId}' should not exist in: {projects!.ToJsonString()}"); } [Fact] diff --git a/backend/Testing/ApiTests/ProjectPermissionTests.cs b/backend/Testing/ApiTests/ProjectPermissionTests.cs index 36f781ffc..4a0bf5c3b 100644 --- a/backend/Testing/ApiTests/ProjectPermissionTests.cs +++ b/backend/Testing/ApiTests/ProjectPermissionTests.cs @@ -1,5 +1,5 @@ using System.Text.Json.Nodes; -using Shouldly; +using FluentAssertions; using Testing.Services; namespace Testing.ApiTests; @@ -56,27 +56,27 @@ ... on Error { private JsonObject GetProject(JsonObject json) { var project = json["data"]!["projectByCode"]?.AsObject(); - project.ShouldNotBeNull(); + project.Should().NotBeNull(); return project; } private void MustHaveMembers(JsonObject project, int? count = null) { var members = project["users"]!.AsArray(); - members.ShouldNotBeNull().ShouldNotBeEmpty(); - if (count is not null) members.Count.ShouldBe(count.Value); + members.Should().NotBeNullOrEmpty(); + if (count is not null) members.Count.Should().Be(count.Value); } private void MustNotHaveMembers(JsonObject project) { var users = project["users"]!.AsArray(); - users.ShouldBeEmpty(); + users.Should().BeEmpty(); } private void MustHaveOnlyUserAsMember(JsonObject project, Guid userId) { var users = project["users"]!.AsArray(); - users.ShouldContain(node => node!["user"]!["id"]!.GetValue() == userId, + users.Should().Contain(node => node!["user"]!["id"]!.GetValue() == userId, "user list " + users.ToJsonString()); } @@ -132,7 +132,7 @@ public async Task ConfidentialProject_NonMemberCannotSeeProject() await LoginAs("user"); var json = await QueryProject(project.Code, expectGqlError: true); var error = json["errors"]!.AsArray().First()?.AsObject(); - error.ShouldNotBeNull(); - error["extensions"]?["code"]?.GetValue().ShouldBe("AUTH_NOT_AUTHORIZED"); + error.Should().NotBeNull(); + error["extensions"]?["code"]?.GetValue().Should().Be("AUTH_NOT_AUTHORIZED"); } } diff --git a/backend/Testing/ApiTests/ResetProjectRaceConditions.cs b/backend/Testing/ApiTests/ResetProjectRaceConditions.cs index 358d96790..cffb0ae1c 100644 --- a/backend/Testing/ApiTests/ResetProjectRaceConditions.cs +++ b/backend/Testing/ApiTests/ResetProjectRaceConditions.cs @@ -1,4 +1,4 @@ -using Shouldly; +using FluentAssertions; using Testing.Fixtures; using static Testing.Services.Utils; @@ -41,9 +41,9 @@ public async Task SimultaneousResetsDontResultIn404s() var lastCommitBefore2 = await _adminApiTester.GetProjectLastCommit(config2.Code); var lastCommitBefore3 = await _adminApiTester.GetProjectLastCommit(config3.Code); - lastCommitBefore1.ShouldBeNullOrWhiteSpace(); - lastCommitBefore2.ShouldBeNullOrWhiteSpace(); - lastCommitBefore3.ShouldBeNullOrWhiteSpace(); + lastCommitBefore1.Should().BeNull(); + lastCommitBefore2.Should().BeNull(); + lastCommitBefore3.Should().BeNull(); // Reset and fill projects on server var newLastCommits = await Task.WhenAll( @@ -52,9 +52,9 @@ public async Task SimultaneousResetsDontResultIn404s() DoFullProjectResetAndVerifyLastCommit(config3.Code) ); - newLastCommits[0].ShouldNotBeNullOrWhiteSpace(); - newLastCommits[0].ShouldBe(newLastCommits[1]); - newLastCommits[0].ShouldBe(newLastCommits[2]); + newLastCommits[0].Should().NotBeNull(); + newLastCommits[0].Should().Be(newLastCommits[1]); + newLastCommits[0].Should().Be(newLastCommits[2]); // we need a short delay between resets or we'll get naming collisions on the backups of the reset projects await Task.Delay(1000); @@ -68,15 +68,15 @@ public async Task SimultaneousResetsDontResultIn404s() ); } - private async Task DoFullProjectResetAndVerifyLastCommit(string projectCode, string? expectedLastCommit = null) + private async Task DoFullProjectResetAndVerifyLastCommit(string projectCode, DateTimeOffset? expectedLastCommit = null) { await _adminApiTester.StartLexboxProjectReset(projectCode); var lastCommitBefore = await _adminApiTester.GetProjectLastCommit(projectCode); - lastCommitBefore.ShouldBeNullOrWhiteSpace(); + lastCommitBefore.Should().BeNull(); await _fixture.FinishLexboxProjectResetWithTemplateRepo(projectCode); var lastCommit = await _adminApiTester.GetProjectLastCommit(projectCode); - if (expectedLastCommit is not null) lastCommit.ShouldBe(expectedLastCommit); - else lastCommit.ShouldNotBeNullOrWhiteSpace(); + if (expectedLastCommit is not null) lastCommit.Should().Be(expectedLastCommit); + else lastCommit.Should().NotBeNull(); return lastCommit; } } diff --git a/backend/Testing/Fixtures/IntegrationFixture.cs b/backend/Testing/Fixtures/IntegrationFixture.cs index df951bb8d..77a1f282a 100644 --- a/backend/Testing/Fixtures/IntegrationFixture.cs +++ b/backend/Testing/Fixtures/IntegrationFixture.cs @@ -1,7 +1,7 @@ using System.IO.Compression; using System.Runtime.CompilerServices; using LexCore.Utils; -using Shouldly; +using FluentAssertions; using Squidex.Assets; using Testing.ApiTests; using Testing.Services; @@ -16,7 +16,7 @@ public class IntegrationFixture : IAsyncLifetime public static readonly DirectoryInfo TemplateRepo = new(Path.Join(BasePath, "_template-repo_")); public ApiTestBase AdminApiTester { get; private set; } = new(); private string? _adminJwt = null; - public string AdminJwt => _adminJwt.ShouldNotBeNull(); + public string AdminJwt => _adminJwt.Should().NotBeNull().And.Subject; static IntegrationFixture() { @@ -69,7 +69,7 @@ public void InitLocalFlexProjectWithRepo(ProjectPath projectPath) var projectDir = Directory.CreateDirectory(projectPath.Dir); FileUtils.CopyFilesRecursively(TemplateRepo, projectDir); File.Move(Path.Join(projectPath.Dir, "kevin-test-01.fwdata"), projectPath.FwDataFile); - Directory.EnumerateFiles(projectPath.Dir).ShouldContain(projectPath.FwDataFile); + Directory.EnumerateFiles(projectPath.Dir).Should().Contain(projectPath.FwDataFile); } public async Task FinishLexboxProjectResetWithTemplateRepo(string projectCode) diff --git a/backend/Testing/Fixtures/IntegrationFixtureTests.cs b/backend/Testing/Fixtures/IntegrationFixtureTests.cs index 18697e956..d606fbacc 100644 --- a/backend/Testing/Fixtures/IntegrationFixtureTests.cs +++ b/backend/Testing/Fixtures/IntegrationFixtureTests.cs @@ -1,5 +1,5 @@ using Moq; -using Shouldly; +using FluentAssertions; using Testing.ApiTests; namespace Testing.Fixtures; @@ -18,7 +18,7 @@ public async Task InitCreatesARepoWithTheProject() await fixture.InitializeAsync(Mock.Of()); IntegrationFixture.TemplateRepo.EnumerateFiles() .Select(f => f.Name) - .ShouldContain("kevin-test-01.fwdata"); + .Should().Contain("kevin-test-01.fwdata"); } [Fact] @@ -27,7 +27,7 @@ public async Task CanFindTheProjectZipFile() await fixture.InitializeAsync(Mock.Of()); IntegrationFixture.TemplateRepoZip .Directory!.EnumerateFiles().Select(f => f.Name) - .ShouldContain(IntegrationFixture.TemplateRepoZip.Name); + .Should().Contain(IntegrationFixture.TemplateRepoZip.Name); } [Fact] @@ -36,6 +36,6 @@ public async Task CanInitFlexProjectRepo() await fixture.InitializeAsync(Mock.Of()); var projectConfig = fixture.InitLocalFlexProjectWithRepo(); Directory.EnumerateFiles(projectConfig.Dir) - .ShouldContain(projectConfig.FwDataFile); + .Should().Contain(projectConfig.FwDataFile); } } diff --git a/backend/Testing/Fixtures/Tests/ServicesFixtureTests.cs b/backend/Testing/Fixtures/Tests/ServicesFixtureTests.cs index 519c396f8..8369b562b 100644 --- a/backend/Testing/Fixtures/Tests/ServicesFixtureTests.cs +++ b/backend/Testing/Fixtures/Tests/ServicesFixtureTests.cs @@ -1,4 +1,4 @@ -using Shouldly; +using FluentAssertions; namespace Testing.Fixtures.Tests; @@ -13,6 +13,6 @@ public async Task CanSetupServices() await fixture.InitializeAsync(); await fixture.DisposeAsync(); }; - Should.CompleteIn(act, TimeSpan.FromSeconds(10)); + await act.Should().CompleteWithinAsync(TimeSpan.FromSeconds(10)); } } diff --git a/backend/Testing/GraphQL/LexAuthUserOutOfSyncExtensionsTests.cs b/backend/Testing/GraphQL/LexAuthUserOutOfSyncExtensionsTests.cs index b8996ea79..3df103e75 100644 --- a/backend/Testing/GraphQL/LexAuthUserOutOfSyncExtensionsTests.cs +++ b/backend/Testing/GraphQL/LexAuthUserOutOfSyncExtensionsTests.cs @@ -1,7 +1,7 @@ using LexBoxApi.GraphQL; using LexCore.Auth; using LexCore.Entities; -using Shouldly; +using FluentAssertions; namespace Testing.GraphQL; @@ -20,10 +20,10 @@ public class LexAuthUserOutOfSyncExtensionsTests public void DetectsUserAddedToProject() { var project = NewProject(); - user.IsOutOfSyncWithProject(project).ShouldBeFalse(); + user.IsOutOfSyncWithProject(project).Should().BeFalse(); project.Users.Add(new() { UserId = user.Id, Role = ProjectRole.Editor }); - user.IsOutOfSyncWithProject(project).ShouldBeTrue(); + user.IsOutOfSyncWithProject(project).Should().BeTrue(); } [Fact] @@ -32,10 +32,10 @@ public void DetectsUserRemovedFromProject() var project = NewProject(); project.Users.Add(new() { UserId = user.Id, Role = ProjectRole.Editor }); var editorUser = user with { Projects = [new AuthUserProject(ProjectRole.Editor, project.Id)] }; - editorUser.IsOutOfSyncWithProject(project).ShouldBeFalse(); + editorUser.IsOutOfSyncWithProject(project).Should().BeFalse(); project.Users.Clear(); - editorUser.IsOutOfSyncWithProject(project).ShouldBeTrue(); + editorUser.IsOutOfSyncWithProject(project).Should().BeTrue(); } [Fact] @@ -45,10 +45,10 @@ public void DetectsUserProjectRoleChanged() var projectUser = new ProjectUsers { UserId = user.Id, Role = ProjectRole.Editor }; project.Users.Add(projectUser); var editorUser = user with { Projects = [new AuthUserProject(ProjectRole.Editor, project.Id)] }; - editorUser.IsOutOfSyncWithProject(project).ShouldBeFalse(); + editorUser.IsOutOfSyncWithProject(project).Should().BeFalse(); projectUser.Role = ProjectRole.Manager; - editorUser.IsOutOfSyncWithProject(project).ShouldBeTrue(); + editorUser.IsOutOfSyncWithProject(project).Should().BeTrue(); } [Fact] @@ -58,7 +58,7 @@ public void DoesNotDetectsUserProjectRoleChangedIfRolesNotAvailable() var projectUser = new ProjectUsers { UserId = user.Id, Role = ProjectRole.Unknown }; project.Users.Add(projectUser); var editorUser = user with { Projects = [new AuthUserProject(ProjectRole.Editor, project.Id)] }; - editorUser.IsOutOfSyncWithProject(project).ShouldBeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithProject(project).Should().BeFalse(); // might be out of sync, but we can't tell } [Fact] @@ -69,7 +69,7 @@ public void DoesNotDetectChangesWithoutProjectUsersIfNotMyProject() project.Users = null!; var editorUser = user with { Projects = [new AuthUserProject(ProjectRole.Editor, project.Id)] }; - editorUser.IsOutOfSyncWithProject(project).ShouldBeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithProject(project).Should().BeFalse(); // might be out of sync, but we can't tell } [Fact] @@ -79,9 +79,9 @@ public void DetectsAddedToMyProjectWithoutProjectUsers() // simulate Users not projected in GQL query project.Users = null!; - user.IsOutOfSyncWithProject(project).ShouldBeFalse(); // might be out of sync, but we can't tell - user.IsOutOfSyncWithProject(project, isMyProject: true).ShouldBeTrue(); - user.IsOutOfSyncWithMyProjects([project]).ShouldBeTrue(); + user.IsOutOfSyncWithProject(project).Should().BeFalse(); // might be out of sync, but we can't tell + user.IsOutOfSyncWithProject(project, isMyProject: true).Should().BeTrue(); + user.IsOutOfSyncWithMyProjects([project]).Should().BeTrue(); } [Fact] @@ -92,18 +92,18 @@ public void DetectsRemovedFromMyProjectWithoutProjectUsers() project.Users = null!; var editorUser = user with { Projects = [new AuthUserProject(ProjectRole.Editor, project.Id)] }; - editorUser.IsOutOfSyncWithProject(project).ShouldBeFalse(); // might be out of sync, but we can't tell - editorUser.IsOutOfSyncWithMyProjects([]).ShouldBeTrue(); + editorUser.IsOutOfSyncWithProject(project).Should().BeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithMyProjects([]).Should().BeTrue(); } [Fact] public void DetectsUserAddedToOrg() { var org = NewOrg(); - user.IsOutOfSyncWithOrg(org).ShouldBeFalse(); + user.IsOutOfSyncWithOrg(org).Should().BeFalse(); org.Members.Add(new() { UserId = user.Id, Role = OrgRole.User }); - user.IsOutOfSyncWithOrg(org).ShouldBeTrue(); + user.IsOutOfSyncWithOrg(org).Should().BeTrue(); } [Fact] @@ -112,10 +112,10 @@ public void DetectsUserRemovedFromOrg() var org = NewOrg(); org.Members.Add(new() { UserId = user.Id, Role = OrgRole.User }); var editorUser = user with { Orgs = [new AuthUserOrg(OrgRole.User, org.Id)] }; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeFalse(); + editorUser.IsOutOfSyncWithOrg(org).Should().BeFalse(); org.Members.Clear(); - editorUser.IsOutOfSyncWithOrg(org).ShouldBeTrue(); + editorUser.IsOutOfSyncWithOrg(org).Should().BeTrue(); } [Fact] @@ -125,10 +125,10 @@ public void DetectsUserOrgRoleChanged() var orgUser = new OrgMember { UserId = user.Id, Role = OrgRole.User }; org.Members.Add(orgUser); var editorUser = user with { Orgs = [new AuthUserOrg(OrgRole.User, org.Id)] }; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeFalse(); + editorUser.IsOutOfSyncWithOrg(org).Should().BeFalse(); orgUser.Role = OrgRole.Admin; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeTrue(); + editorUser.IsOutOfSyncWithOrg(org).Should().BeTrue(); } [Fact] @@ -138,7 +138,7 @@ public void DoesNotDetectsUserOrgRoleChangedIfRolesNotAvailable() var orgUser = new OrgMember { UserId = user.Id, Role = OrgRole.Unknown }; org.Members.Add(orgUser); var editorUser = user with { Orgs = [new AuthUserOrg(OrgRole.User, org.Id)] }; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithOrg(org).Should().BeFalse(); // might be out of sync, but we can't tell } [Fact] @@ -147,10 +147,10 @@ public void DetectsChangesWithOrgProjects() var org = NewOrg(); var project = NewProject(); org.Projects = [project]; - user.IsOutOfSyncWithOrg(org).ShouldBeFalse(); + user.IsOutOfSyncWithOrg(org).Should().BeFalse(); project.Users.Add(new() { UserId = user.Id, Role = ProjectRole.Editor }); - user.IsOutOfSyncWithOrg(org).ShouldBeTrue(); + user.IsOutOfSyncWithOrg(org).Should().BeTrue(); } [Fact] @@ -161,7 +161,7 @@ public void DoesNotDetectChangesWithoutOrgMembersIfNotMyOrg() org.Members = null!; var editorUser = user with { Orgs = [new AuthUserOrg(OrgRole.User, org.Id)] }; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithOrg(org).Should().BeFalse(); // might be out of sync, but we can't tell } [Fact] @@ -171,9 +171,9 @@ public void DetectsAddedToMyOrgWithoutOrgMembers() // simulate Members not projected in GQL query org.Members = null!; - user.IsOutOfSyncWithOrg(org).ShouldBeFalse(); // might be out of sync, but we can't tell - user.IsOutOfSyncWithOrg(org, isMyOrg: true).ShouldBeTrue(); - user.IsOutOfSyncWithMyOrgs([org]).ShouldBeTrue(); + user.IsOutOfSyncWithOrg(org).Should().BeFalse(); // might be out of sync, but we can't tell + user.IsOutOfSyncWithOrg(org, isMyOrg: true).Should().BeTrue(); + user.IsOutOfSyncWithMyOrgs([org]).Should().BeTrue(); } [Fact] @@ -184,8 +184,8 @@ public void DetectsRemovedFromMyOrgWithoutOrgMembers() org.Members = null!; var editorUser = user with { Orgs = [new AuthUserOrg(OrgRole.User, org.Id)] }; - editorUser.IsOutOfSyncWithOrg(org).ShouldBeFalse(); // might be out of sync, but we can't tell - editorUser.IsOutOfSyncWithMyOrgs([]).ShouldBeTrue(); + editorUser.IsOutOfSyncWithOrg(org).Should().BeFalse(); // might be out of sync, but we can't tell + editorUser.IsOutOfSyncWithMyOrgs([]).Should().BeTrue(); } private static Project NewProject() diff --git a/backend/Testing/LexCore/CrdtServerCommitTests.cs b/backend/Testing/LexCore/CrdtServerCommitTests.cs index 4deff4c38..31ed6c747 100644 --- a/backend/Testing/LexCore/CrdtServerCommitTests.cs +++ b/backend/Testing/LexCore/CrdtServerCommitTests.cs @@ -4,7 +4,7 @@ using LexData.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using Shouldly; +using FluentAssertions; using Testing.Fixtures; namespace Testing.LexCore; @@ -71,8 +71,8 @@ public async Task CanRoundTripCommitChanges() await _dbContext.SaveChangesAsync(); var actualCommit = await _dbContext.Set().AsNoTracking().FirstAsync(c => c.Id == commitId); - actualCommit.ShouldNotBeSameAs(expectedCommit); - JsonSerializer.Serialize(actualCommit.ChangeEntities[0].Change).ShouldBe(changeJson); + actualCommit.Should().NotBeSameAs(expectedCommit); + JsonSerializer.Serialize(actualCommit.ChangeEntities[0].Change).Should().Be(changeJson); } [Fact] @@ -80,6 +80,6 @@ public void TypePropertyShouldAlwaysBeFirst() { var changeJson = """{"name":"Joe","$type":"test"}"""; var jsonChange = JsonSerializer.Deserialize(changeJson); - JsonSerializer.Serialize(jsonChange).ShouldBe("""{"$type":"test","name":"Joe"}"""); + JsonSerializer.Serialize(jsonChange).Should().Be("""{"$type":"test","name":"Joe"}"""); } } diff --git a/backend/Testing/LexCore/LexAuthUserTests.cs b/backend/Testing/LexCore/LexAuthUserTests.cs index 967db437a..ed919e901 100644 --- a/backend/Testing/LexCore/LexAuthUserTests.cs +++ b/backend/Testing/LexCore/LexAuthUserTests.cs @@ -12,7 +12,8 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Logging; using Microsoft.IdentityModel.Tokens; -using Shouldly; +using FluentAssertions; +using FluentAssertions.Execution; namespace Testing.LexCore; @@ -58,12 +59,13 @@ public void CanGetClaimsFromUser() var emailClaim = new Claim(LexAuthConstants.EmailClaimType, _user.Email); var roleClaim = new Claim(LexAuthConstants.RoleClaimType, _user.Role.ToString()); var projectClaim = new Claim("proj", _user.ProjectsJson); - claims.ShouldSatisfyAllConditions( - () => claims.ShouldContain(idClaim.ToString()), - () => claims.ShouldContain(emailClaim.ToString()), - () => claims.ShouldContain(roleClaim.ToString()), - () => claims.ShouldContain(projectClaim.ToString()) - ); + using (new AssertionScope()) + { + claims.Should().Contain(idClaim.ToString()); + claims.Should().Contain(emailClaim.ToString()); + claims.Should().Contain(roleClaim.ToString()); + claims.Should().Contain(projectClaim.ToString()); + } } [Fact] @@ -71,7 +73,7 @@ public void CanRoundTripClaimsThroughAPrincipal() { var claims = _user.GetPrincipal("Testing"); var newUser = LexAuthUser.FromClaimsPrincipal(claims); - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } [Fact] @@ -83,7 +85,7 @@ public void CanRoundTripClaimsThroughJwt() var outputJwt = tokenHandler.ReadJwtToken(encodedJwt); var principal = new ClaimsPrincipal(new ClaimsIdentity(outputJwt.Claims, "Testing")); var newUser = LexAuthUser.FromClaimsPrincipal(principal); - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } [Fact] @@ -105,11 +107,11 @@ public void CanRoundTripClaimsWhenUsingSecurityTokenDescriptor() ); var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.ReadJwtToken(jwt); - token.ValidTo.ShouldBe(expires.DateTime); - token.ValidFrom.ShouldBe(issuedAt.DateTime); - token.IssuedAt.ShouldBe(issuedAt.DateTime); + token.ValidTo.Should().Be(expires.DateTime); + token.ValidFrom.Should().Be(issuedAt.DateTime); + token.IssuedAt.Should().Be(issuedAt.DateTime); //props get converted to claims, but some we want to exclude because they are used elsewhere. - token.Claims.ShouldNotContain(c => c.Type == "props.issued" || c.Type == "props.expires"); + token.Claims.Should().NotContain(c => c.Type == "props.issued" || c.Type == "props.expires"); var json = Base64UrlEncoder.Decode(token.RawPayload); LexAuthUser? newUser; @@ -122,7 +124,7 @@ public void CanRoundTripClaimsWhenUsingSecurityTokenDescriptor() throw new JsonException("Could not deserialize user, json: " + json, e); } - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } [Fact] @@ -149,15 +151,15 @@ public void CanRoundTripFromAuthTicketToAuthTicket() jwtUserOptions ); var actualTicket = JwtTicketDataFormat.ConvertJwtToAuthTicket(jwt, JwtBearerOptions, NullLogger.Instance); - actualTicket.ShouldNotBeNull(); - actualTicket.Properties.IssuedUtc.ShouldBe(ticket.Properties.IssuedUtc); - actualTicket.Properties.ExpiresUtc.ShouldBe(ticket.Properties.ExpiresUtc); + actualTicket.Should().NotBeNull(); + actualTicket.Properties.IssuedUtc.Should().Be(ticket.Properties.IssuedUtc); + actualTicket.Properties.ExpiresUtc.Should().Be(ticket.Properties.ExpiresUtc); //order by is because the order isn't important but the assertion fails if the order is different actualTicket.Properties.Items.OrderBy(kvp => kvp.Key) - .ShouldBe(ticket.Properties.Items.OrderBy(kvp => kvp.Key)); + .Should().Equal(ticket.Properties.Items.OrderBy(kvp => kvp.Key)); var newUser = LexAuthUser.FromClaimsPrincipal(actualTicket.Principal); - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } [Fact] @@ -169,7 +171,7 @@ public void CanRoundTripJwtFromUserThroughLexAuthService() var outputJwt = tokenHandler.ReadJwtToken(jwt); var principal = new ClaimsPrincipal(new ClaimsIdentity(outputJwt.Claims, "Testing")); var newUser = LexAuthUser.FromClaimsPrincipal(principal); - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } private const string knownGoodJwt = @@ -182,12 +184,12 @@ public void CanParseFromKnownGoodJwt() var outputJwt = tokenHandler.ReadJwtToken(knownGoodJwt); var principal = new ClaimsPrincipal(new ClaimsIdentity(outputJwt.Claims, "Testing")); var newUser = LexAuthUser.FromClaimsPrincipal(principal); - newUser.ShouldNotBeNull(); - newUser.UpdatedDate.ShouldBe(0); + newUser.Should().NotBeNull(); + newUser.UpdatedDate.Should().Be(0); //old jwt doesn't have updated date or orgs, we're ok with that so we correct the values to make the equivalence work newUser.Orgs = [ new AuthUserOrg(OrgRole.Admin, LexData.SeedingData.TestOrgId) ]; newUser.UpdatedDate = _user.UpdatedDate; - newUser.ShouldBeEquivalentTo(_user); + newUser.Should().BeEquivalentTo(_user); } [Fact] @@ -200,7 +202,7 @@ public void CheckingJwtLength() .ToArray() }; var (jwt, _, _) = _lexAuthService.GenerateJwt(user); - jwt.Length.ShouldBeLessThan(LexAuthUser.MaxJwtLength); + jwt.Length.Should().BeLessThan(LexAuthUser.MaxJwtLength); } [Fact] @@ -223,6 +225,6 @@ public void CanRoundTripThroughRefresh() var loggedInPrincipal = new ClaimsPrincipal(new ClaimsIdentity(tokenHandler.ReadJwtToken(redirectJwt).Claims, "Testing")); var newUser = LexAuthUser.FromClaimsPrincipal(loggedInPrincipal); - newUser.ShouldBeEquivalentTo(_user with { Audience = LexboxAudience.ForgotPassword }); + newUser.Should().BeEquivalentTo(_user with { Audience = LexboxAudience.ForgotPassword }); } } diff --git a/backend/Testing/LexCore/PasswordHashingTests.cs b/backend/Testing/LexCore/PasswordHashingTests.cs index 1ce079acb..4d33b9a37 100644 --- a/backend/Testing/LexCore/PasswordHashingTests.cs +++ b/backend/Testing/LexCore/PasswordHashingTests.cs @@ -1,5 +1,5 @@ using LexCore; -using Shouldly; +using FluentAssertions; namespace Testing.LexCore; @@ -10,6 +10,6 @@ public class PasswordHashingTests [Theory] public void CanHashPassword(string pw, string salt, string hash) { - PasswordHashing.RedminePasswordHash(pw, salt, false).ShouldBe(hash); + PasswordHashing.RedminePasswordHash(pw, salt, false).Should().Be(hash); } -} \ No newline at end of file +} diff --git a/backend/Testing/LexCore/ProjectCodeTests.cs b/backend/Testing/LexCore/ProjectCodeTests.cs index 49b387bfa..6f6945adf 100644 --- a/backend/Testing/LexCore/ProjectCodeTests.cs +++ b/backend/Testing/LexCore/ProjectCodeTests.cs @@ -1,5 +1,5 @@ using LexCore.Entities; -using Shouldly; +using FluentAssertions; namespace Testing.LexCore; @@ -29,7 +29,7 @@ public void InvalidCodesThrows(string code) public void ValidCodes(string code) { var projectCode = new ProjectCode(code); - projectCode.Value.ShouldBe(code); - projectCode.ToString().ShouldBe(code); + projectCode.Value.Should().Be(code); + projectCode.ToString().Should().Be(code); } } diff --git a/backend/Testing/LexCore/Services/HgServiceTests.cs b/backend/Testing/LexCore/Services/HgServiceTests.cs index 4372635f4..e3ff8e0f1 100644 --- a/backend/Testing/LexCore/Services/HgServiceTests.cs +++ b/backend/Testing/LexCore/Services/HgServiceTests.cs @@ -1,15 +1,13 @@ using System.IO.Compression; using LexBoxApi.Services; using LexCore.Config; -using LexCore.Entities; using LexCore.Exceptions; using LexSyncReverseProxy; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using Moq.Contrib.HttpClient; -using Shouldly; -using Testing.Fixtures; +using FluentAssertions; namespace Testing.LexCore.Services; @@ -59,7 +57,7 @@ private void CleanUpTempDir() [InlineData(HgType.resumable, LexboxResumable)] public void DetermineProjectPrefixWorks(HgType type, string expectedUrl) { - HgService.DetermineProjectUrlPrefix(type, _hgConfig).ShouldBe(expectedUrl); + HgService.DetermineProjectUrlPrefix(type, _hgConfig).Should().Be(expectedUrl); } [Theory] @@ -82,7 +80,7 @@ public void HgDatesConvertedAccurately(string? input, string? expectedStr) { DateTimeOffset? expected = expectedStr == null ? null : DateTimeOffset.Parse(expectedStr); var actual = HgService.ConvertHgDate(input); - actual.ShouldBe(expected); + actual.Should().Be(expected); } [Theory] @@ -108,7 +106,7 @@ public async Task CanFinishResetByUnZippingAnArchive(string filePath) var repoPath = Path.GetFullPath(Path.Join(_hgConfig.RepoPath, "u", code)); Directory.EnumerateFiles(repoPath, "*", SearchOption.AllDirectories) .Select(p => Path.GetRelativePath(repoPath, p)) - .ShouldHaveSingleItem().ShouldBe(Path.Join(".hg", "important-file.bin")); + .Should().ContainSingle().Which.Should().Be(Path.Join(".hg", "important-file.bin")); } [Theory] @@ -143,6 +141,6 @@ public async Task ThrowsIfNoHgFolderIsFound() stream.Position = 0; var act = () => _hgService.FinishReset(code, stream); - act.ShouldThrow(); + await act.Should().ThrowAsync(); } } diff --git a/backend/Testing/LexCore/Services/ProjectServiceTest.cs b/backend/Testing/LexCore/Services/ProjectServiceTest.cs index 48dcc9739..6accdbbe8 100644 --- a/backend/Testing/LexCore/Services/ProjectServiceTest.cs +++ b/backend/Testing/LexCore/Services/ProjectServiceTest.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using Npgsql; -using Shouldly; +using FluentAssertions; using Testing.Fixtures; namespace Testing.LexCore.Services; @@ -51,7 +51,7 @@ public async Task CanCreateProject() { var projectId = await _projectService.CreateProject( new(null, "TestProject", "Test", "test1", ProjectType.FLEx, RetentionPolicy.Test, false, null, null)); - projectId.ShouldNotBe(default); + projectId.Should().NotBe(Guid.Empty); } [Fact] @@ -61,8 +61,8 @@ public async Task CanUpdateProjectLangTags() new(null, "TestProject", "Test", "test2", ProjectType.FLEx, RetentionPolicy.Test, false, null, null)); await _projectService.UpdateProjectLangTags(projectId); var project = await _lexBoxDbContext.Projects.Include(p => p.FlexProjectMetadata).SingleAsync(p => p.Id == projectId); - project.FlexProjectMetadata.ShouldNotBeNull(); - project.FlexProjectMetadata.WritingSystems.ShouldBeEquivalentTo(_writingSystems); + project.FlexProjectMetadata.Should().NotBeNull(); + project.FlexProjectMetadata.WritingSystems.Should().BeEquivalentTo(_writingSystems); } [Fact] @@ -72,11 +72,12 @@ public async Task ShouldErrorIfCreatingAProjectWithTheSameCode() await _projectService.CreateProject( new(null, "TestProject", "Test", "test-dup-code", ProjectType.FLEx, RetentionPolicy.Test, false, null, null)); - var exception = await _projectService.CreateProject( + var act = () => _projectService.CreateProject( new(null, "Test2", "Test desc", "test-dup-code", ProjectType.Unknown, RetentionPolicy.Dev, false, null, null) - ).ShouldThrowAsync(); + ); - exception.InnerException.ShouldBeOfType() - .SqlState.ShouldBe(PostgresErrorCodes.UniqueViolation); + (await act.Should().ThrowAsync()) + .WithInnerException() + .Which.SqlState.Should().Be(PostgresErrorCodes.UniqueViolation); } } diff --git a/backend/Testing/LexCore/Utils/ConcurrentWeakDictionaryTests.cs b/backend/Testing/LexCore/Utils/ConcurrentWeakDictionaryTests.cs index 1ac10e717..58dbb9699 100644 --- a/backend/Testing/LexCore/Utils/ConcurrentWeakDictionaryTests.cs +++ b/backend/Testing/LexCore/Utils/ConcurrentWeakDictionaryTests.cs @@ -1,5 +1,5 @@ using LexCore.Utils; -using Shouldly; +using FluentAssertions; namespace Testing.LexCore.Utils; @@ -12,8 +12,8 @@ public void Add_Then_Try_Get_Value_Test() var obj = new object(); var dict = new ConcurrentWeakDictionary(); dict.Add("key", obj); - dict.TryGetValue("key", out var value).ShouldBeTrue(); - value.ShouldBe(obj); + dict.TryGetValue("key", out var value).Should().BeTrue(); + value.Should().Be(obj); } [Fact] @@ -25,9 +25,9 @@ public void GetOrAdd_New_Key_Should_Add_And_Return_New_Value_Test() var returnedValue = dictionary.GetOrAdd("key", k => value); - returnedValue.ShouldBe(value); - dictionary.TryGetValue("key", out var existingValue).ShouldBeTrue(); - existingValue.ShouldBe(value); + returnedValue.Should().Be(value); + dictionary.TryGetValue("key", out var existingValue).Should().BeTrue(); + existingValue.Should().Be(value); } [Fact] @@ -41,9 +41,9 @@ public void GetOrAdd_Existing_Key_Should_Return_Existing_Value_Test() var returnedValue = dictionary.GetOrAdd(key, k => new object()); - returnedValue.ShouldBe(value); - dictionary.TryGetValue(key, out var existingValue).ShouldBeTrue(); - existingValue.ShouldBe(value); + returnedValue.Should().Be(value); + dictionary.TryGetValue(key, out var existingValue).Should().BeTrue(); + existingValue.Should().Be(value); } private ConcurrentWeakDictionary Setup(string key) @@ -69,6 +69,6 @@ public void Add_Then_Collect_And_Check_That_Key_Is_Removed_Test() GC.WaitForPendingFinalizers(); // Check that the value for the key no longer exists. - dictionary.TryGetValue(key, out var result).ShouldBeFalse(); + dictionary.TryGetValue(key, out var result).Should().BeFalse(); } } diff --git a/backend/Testing/LexCore/Utils/GqlUtils.cs b/backend/Testing/LexCore/Utils/GqlUtils.cs index b67c4597a..de2c0eb73 100644 --- a/backend/Testing/LexCore/Utils/GqlUtils.cs +++ b/backend/Testing/LexCore/Utils/GqlUtils.cs @@ -1,5 +1,5 @@ using System.Text.Json.Nodes; -using Shouldly; +using FluentAssertions; namespace Testing.LexCore.Utils; @@ -9,13 +9,13 @@ public static void ValidateGqlErrors(JsonObject json, bool expectError = false) { if (!expectError) { - json["errors"].ShouldBeNull(); + json!["errors"]?.Should().BeNull(); if (json["data"] is JsonObject data) { foreach (var (_, resultValue) in data) { if (resultValue is JsonObject resultObject) - resultObject["errors"].ShouldBeNull(); + resultObject["errors"]?.Should().BeNull(); } } } @@ -37,7 +37,7 @@ public static void ValidateGqlErrors(JsonObject json, bool expectError = false) } } } - foundError.ShouldBeTrue(); + foundError.Should().BeTrue(); } } } diff --git a/backend/Testing/Services/CleanupResetProjectsTests.cs b/backend/Testing/Services/CleanupResetProjectsTests.cs index 6946903d5..431d2b1de 100644 --- a/backend/Testing/Services/CleanupResetProjectsTests.cs +++ b/backend/Testing/Services/CleanupResetProjectsTests.cs @@ -1,6 +1,6 @@ using LexBoxApi.Services; using LexCore.Utils; -using Shouldly; +using FluentAssertions; namespace Testing.Services; @@ -12,8 +12,8 @@ public void ResetRegexCanFindTimestampFromResetRepoName() var date = DateTimeOffset.UtcNow; var repoName = HgService.DeletedRepoName("test", HgService.ResetSoftDeleteSuffix(date)); var match = HgService.ResetProjectsRegex().Match(repoName); - match.Success.ShouldBeTrue(); - match.Groups[1].Value.ShouldBe(FileUtils.ToTimestamp(date)); + match.Success.Should().BeTrue(); + match.Groups[1].Value.Should().Be(FileUtils.ToTimestamp(date)); } [Fact] @@ -22,8 +22,8 @@ public void CanGetDateFromResetRepoName() var expected = DateTimeOffset.Now; var repoName = HgService.DeletedRepoName("test", HgService.ResetSoftDeleteSuffix(expected)); var actual = HgService.GetResetDate(repoName); - actual.ShouldNotBeNull(); - TruncateToMinutes(actual.Value).ShouldBe(TruncateToMinutes(expected)); + actual.Should().NotBeNull(); + TruncateToMinutes(actual!.Value).Should().Be(TruncateToMinutes(expected)); } private DateTimeOffset TruncateToMinutes(DateTimeOffset date) @@ -36,8 +36,8 @@ private DateTimeOffset TruncateToMinutes(DateTimeOffset date) public void ResetRegexCanFindTimestamp(string repoName, string timestamp) { var match = HgService.ResetProjectsRegex().Match(repoName); - match.Success.ShouldBeTrue(); - match.Groups[1].Value.ShouldBe(timestamp); + match.Success.Should().BeTrue(); + match.Groups[1].Value.Should().Be(timestamp); } [Theory] @@ -47,7 +47,7 @@ public void ResetRegexCanFindTimestamp(string repoName, string timestamp) public void ResetRegexDoesNotMatchNonResets(string repoName) { var match = HgService.ResetProjectsRegex().Match(repoName); - match.Success.ShouldBeFalse(); + match.Success.Should().BeFalse(); } } diff --git a/backend/Testing/Services/IsLanguageForgeProjectDataLoaderTests.cs b/backend/Testing/Services/IsLanguageForgeProjectDataLoaderTests.cs index 8f48a0929..3d16d6902 100644 --- a/backend/Testing/Services/IsLanguageForgeProjectDataLoaderTests.cs +++ b/backend/Testing/Services/IsLanguageForgeProjectDataLoaderTests.cs @@ -1,7 +1,7 @@ using LexBoxApi.GraphQL.CustomTypes; using Microsoft.Extensions.Time.Testing; using Polly; -using Shouldly; +using FluentAssertions; namespace Testing.Services; @@ -36,14 +36,14 @@ private ValueTask>> Execute(Exception? exceptio private void VerifyEmptyResult(Outcome> result) { - result.Exception.ShouldBeNull(); - result.Result.ShouldBe(new Dictionary() { { "test", false } }); + result.Exception.Should().BeNull(); + result.Result.Should().BeEquivalentTo(new Dictionary() { { "test", false } }); } private void VerifySuccessResult(Outcome> result) { - result.Exception.ShouldBeNull(); - result.Result.ShouldBe(new Dictionary() { { "test", true } }); + result.Exception.Should().BeNull(); + result.Result.Should().BeEquivalentTo(new Dictionary() { { "test", true } }); } [Fact] diff --git a/backend/Testing/Services/JwtHelper.cs b/backend/Testing/Services/JwtHelper.cs index af6a8172a..5f839c832 100644 --- a/backend/Testing/Services/JwtHelper.cs +++ b/backend/Testing/Services/JwtHelper.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Http.Resilience; using Mono.Unix.Native; using Polly; -using Shouldly; +using FluentAssertions; using Testing.ApiTests; namespace Testing.Services; @@ -58,7 +58,7 @@ public static async Task ExecuteLogin(SendReceiveAuth auth, public static string GetJwtFromLoginResponse(HttpResponseMessage response) { TryGetJwtFromLoginResponse(response, out var jwt); - jwt.ShouldNotBeNullOrEmpty(); + jwt.Should().NotBeNullOrEmpty(); return jwt; } diff --git a/backend/Testing/Services/SendReceiveService.cs b/backend/Testing/Services/SendReceiveService.cs index aabf4ea7f..778f0369b 100644 --- a/backend/Testing/Services/SendReceiveService.cs +++ b/backend/Testing/Services/SendReceiveService.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using Chorus; using Nini.Ini; -using Shouldly; +using FluentAssertions; using SIL.Progress; using Testing.Logging; using Xunit.Abstractions; @@ -86,19 +86,19 @@ public string RunCloneSendReceive(SendReceiveParams sendReceiveParams, SendRecei // Clone var cloneResult = CloneProject(sendReceiveParams, auth); - Directory.Exists(projectDir).ShouldBeTrue($"Directory {projectDir} not found. Clone response: {cloneResult}"); - Directory.EnumerateFiles(projectDir).ShouldContain(fwDataFile); + Directory.Exists(projectDir).Should().BeTrue($"Directory {projectDir} not found. Clone response: {cloneResult}"); + Directory.EnumerateFiles(projectDir).Should().Contain(fwDataFile); var fwDataFileInfo = new FileInfo(fwDataFile); - fwDataFileInfo.Length.ShouldBeGreaterThan(0); + fwDataFileInfo.Length.Should().BeGreaterThan(0); var fwDataFileOriginalLength = fwDataFileInfo.Length; // SendReceive var srResult = SendReceiveProject(sendReceiveParams, auth); - srResult.ShouldContain("no changes from others"); + srResult.Should().Contain("No changes from others"); fwDataFileInfo.Refresh(); - fwDataFileInfo.Exists.ShouldBeTrue(); - fwDataFileInfo.Length.ShouldBe(fwDataFileOriginalLength); + fwDataFileInfo.Exists.Should().BeTrue(); + fwDataFileInfo.Length.Should().Be(fwDataFileOriginalLength); return $"Clone: {cloneResult}{Environment.NewLine}SendReceive: {srResult}"; } diff --git a/backend/Testing/Services/Utils.cs b/backend/Testing/Services/Utils.cs index dfea6d1bd..d70df9fbb 100644 --- a/backend/Testing/Services/Utils.cs +++ b/backend/Testing/Services/Utils.cs @@ -2,7 +2,7 @@ using System.Text.RegularExpressions; using LexCore.Entities; using Quartz.Util; -using Shouldly; +using FluentAssertions; using Testing.ApiTests; using static Testing.Services.Constants; @@ -111,9 +111,9 @@ ... on InvalidEmailError { public static void ValidateSendReceiveOutput(string srOutput) { - srOutput.ShouldNotContain("abort"); - srOutput.ShouldNotContain("failure"); - srOutput.ShouldNotContain("error"); + srOutput.Should().NotContain("abort"); + srOutput.Should().NotContain("failure"); + srOutput.Should().NotContain("error"); } public static string ToProjectCodeFriendlyString(string name) @@ -137,7 +137,7 @@ private static string GetNewProjectDir(string projectCode, var randomIndexedId = $"{_folderIndex++}-{Guid.NewGuid().ToString().Split("-")[0]}"; //fwdata file containing folder name will be the same as the file name projectDir = Path.Join(projectDir, randomIndexedId, projectCode); - projectDir.Length.ShouldBeLessThan(150, $"Path may be too long with mercurial directories {projectDir}"); + projectDir.Length.Should().BeLessThan(150, $"Path may be too long with mercurial directories {projectDir}"); return projectDir; } } diff --git a/backend/Testing/Services/UtilsTests.cs b/backend/Testing/Services/UtilsTests.cs index 0d52a5875..81801b647 100644 --- a/backend/Testing/Services/UtilsTests.cs +++ b/backend/Testing/Services/UtilsTests.cs @@ -1,4 +1,4 @@ -using Shouldly; +using FluentAssertions; using Testing.SyncReverseProxy; namespace Testing.Services; @@ -14,6 +14,6 @@ public class UtilsTests [InlineData("SimultaneousResetsDontResultIn404S", "simultaneous-resets-dont-result-in-404-s")] public void VerifyToProjectCodeFriendlyString(string input, string expected) { - Utils.ToProjectCodeFriendlyString(input).ShouldBe(expected); + Utils.ToProjectCodeFriendlyString(input).Should().Be(expected); } } diff --git a/backend/Testing/SyncReverseProxy/LegacyProjectApiTests.cs b/backend/Testing/SyncReverseProxy/LegacyProjectApiTests.cs index 5a3b47712..ab48a04d8 100644 --- a/backend/Testing/SyncReverseProxy/LegacyProjectApiTests.cs +++ b/backend/Testing/SyncReverseProxy/LegacyProjectApiTests.cs @@ -1,9 +1,9 @@ using System.Net; using System.Net.Http.Json; -using System.Text; using System.Text.Json; using System.Text.Json.Nodes; -using Shouldly; +using FluentAssertions; +using FluentAssertions.Execution; using Testing.ApiTests; using Testing.Services; @@ -28,27 +28,28 @@ public class LegacyProjectApiTests private async Task ValidateResponse(HttpResponseMessage response) { - response.StatusCode.ShouldBe(HttpStatusCode.OK); + response.StatusCode.Should().Be(HttpStatusCode.OK); var content = await response.Content.ReadFromJsonAsync(); - content.ValueKind.ShouldBe(JsonValueKind.Array); + content.ValueKind.Should().Be(JsonValueKind.Array); var projectArray = JsonArray.Create(content); - projectArray.ShouldNotBeNull(); - projectArray.Count.ShouldBeGreaterThan(0); + projectArray.Should().NotBeNull(); + projectArray.Count.Should().BeGreaterThan(0); var project = projectArray.First(p => p?["identifier"]?.GetValue() == TestingEnvironmentVariables.ProjectCode) as JsonObject; - project.ShouldNotBeNull(); + project.Should().NotBeNull(); var projectDict = new Dictionary(project); - projectDict.ShouldSatisfyAllConditions( - () => projectDict.ShouldContainKey("identifier"), - () => projectDict.ShouldContainKey("name"), - () => projectDict.ShouldContainKey("repository"), - () => projectDict.ShouldContainKey("role") - ); - project["identifier"]!.GetValue().ShouldBe(TestingEnvironmentVariables.ProjectCode); - project["name"]!.GetValue().ShouldBe("Sena 3"); - project["repository"]!.GetValue().ShouldBe("http://public.languagedepot.org"); + using (new AssertionScope()) + { + projectDict.Should().ContainKey("identifier"); + projectDict.Should().ContainKey("name"); + projectDict.Should().ContainKey("repository"); + projectDict.Should().ContainKey("role"); + } + project["identifier"]!.GetValue().Should().Be(TestingEnvironmentVariables.ProjectCode); + project["name"]!.GetValue().Should().Be("Sena 3"); + project["repository"]!.GetValue().Should().Be("http://public.languagedepot.org"); //todo what is role for? returns unknown in my single test - project["role"]!.GetValue().ShouldNotBeEmpty(); + project["role"]!.GetValue().Should().NotBeEmpty(); } [Fact] @@ -96,13 +97,13 @@ public async Task TestInvalidPassword() $"{_baseUrl}/api/user/{TestData.User}/projects", new FormUrlEncodedContent( new[] { new KeyValuePair("password", "bad password") })); - response.StatusCode.ShouldBe(HttpStatusCode.Forbidden); + response.StatusCode.Should().Be(HttpStatusCode.Forbidden); var content = await response.Content.ReadFromJsonAsync(); - content.ValueKind.ShouldBe(JsonValueKind.Object); + content.ValueKind.Should().Be(JsonValueKind.Object); var responseObject = JsonObject.Create(content); - responseObject.ShouldNotBeNull(); - responseObject.ShouldContainKey("error"); - responseObject["error"]!.GetValue().ShouldBe("Bad password"); + responseObject.Should().NotBeNull(); + responseObject.Should().ContainKey("error"); + responseObject["error"]!.GetValue().Should().Be("Bad password"); } [Fact] @@ -112,13 +113,13 @@ public async Task TestInvalidUser() $"{_baseUrl}/api/user/not-a-real-user-account/projects", new FormUrlEncodedContent( new[] { new KeyValuePair("password", "doesn't matter") })); - response.StatusCode.ShouldBe(HttpStatusCode.NotFound); + response.StatusCode.Should().Be(HttpStatusCode.NotFound); var content = await response.Content.ReadFromJsonAsync(); - content.ValueKind.ShouldBe(JsonValueKind.Object); + content.ValueKind.Should().Be(JsonValueKind.Object); var responseObject = JsonObject.Create(content); - responseObject.ShouldNotBeNull(); - responseObject.ShouldContainKey("error"); - responseObject["error"]!.GetValue().ShouldBe("Unknown user"); + responseObject.Should().NotBeNull(); + responseObject.Should().ContainKey("error"); + responseObject["error"]!.GetValue().Should().Be("Unknown user"); } // LF sends lots of requests with no password/request body. Chorus might as well. @@ -127,6 +128,6 @@ public async Task TestInvalidUser() public async Task MissingPasswordReturns403() { var response = await Client.PostAsJsonAsync($"{_baseUrl}/api/user/{TestData.User}/projects", null); - response.StatusCode.ShouldBe(HttpStatusCode.Forbidden); + response.StatusCode.Should().Be(HttpStatusCode.Forbidden); } } diff --git a/backend/Testing/SyncReverseProxy/ProxyHgRequestTests.cs b/backend/Testing/SyncReverseProxy/ProxyHgRequestTests.cs index d5afda11b..7f808c870 100644 --- a/backend/Testing/SyncReverseProxy/ProxyHgRequestTests.cs +++ b/backend/Testing/SyncReverseProxy/ProxyHgRequestTests.cs @@ -3,7 +3,7 @@ using System.Net.Http.Json; using System.Text; using LexBoxApi.Auth; -using Shouldly; +using FluentAssertions; using Testing.ApiTests; using Testing.Services; @@ -18,7 +18,7 @@ public class ProxyHgRequests private void ShouldBeValidResponse(HttpResponseMessage responseMessage) { //the Basic realm part is required by the HG client, otherwise it won't request again with a basic auth header - responseMessage.Headers.WwwAuthenticate.ToString().ShouldContain("Basic realm=\""); + responseMessage.Headers.WwwAuthenticate.ToString().Should().Contain("Basic realm=\""); } [Theory] @@ -35,7 +35,7 @@ public async Task TestGet(string user) Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{TestData.Password}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); + responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); } [Fact] @@ -50,7 +50,7 @@ public async Task TestGetPrefixHg() Convert.ToBase64String(Encoding.ASCII.GetBytes($"{TestData.User}:{TestData.Password}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); + responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); } [Theory] @@ -59,7 +59,7 @@ public async Task TestGetPrefixHg() public async Task TestGetWithJwtInBasicAuth(string user) { var jwt = await JwtHelper.GetJwtForUser(new(user, TestData.Password)); - jwt.ShouldNotBeNullOrEmpty(); + jwt.Should().NotBeNullOrEmpty(); var responseMessage = await Client.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/{TestingEnvironmentVariables.ProjectCode}") @@ -69,7 +69,7 @@ public async Task TestGetWithJwtInBasicAuth(string user) Authorization = new ("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"bearer:{jwt}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); + responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); } [Fact] @@ -85,7 +85,7 @@ public async Task TestGetBadPassword() Convert.ToBase64String(Encoding.ASCII.GetBytes($"{TestData.User}:{password}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); ShouldBeValidResponse(responseMessage); } @@ -95,7 +95,7 @@ public async Task TestNoAuthResponse() var responseMessage = await Client.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/{TestingEnvironmentVariables.ProjectCode}")); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); ShouldBeValidResponse(responseMessage); } @@ -112,9 +112,9 @@ public async Task SimpleClone() }; batchRequest.Headers.Add("x-hgarg-1", "cmds=heads+%3Bknown+nodes%3D"); var batchResponse = await Client.SendAsync(batchRequest); - batchResponse.StatusCode.ShouldBe(HttpStatusCode.OK); + batchResponse.StatusCode.Should().Be(HttpStatusCode.OK); var batchBody = await batchResponse.Content.ReadAsStringAsync(); - batchBody.ShouldEndWith(";"); + batchBody.Should().EndWith(";"); var heads = batchBody.Split('\n')[^2]; var getBundleRequest = new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/{projectCode}?cmd=getbundle") diff --git a/backend/Testing/SyncReverseProxy/ResumableTests.cs b/backend/Testing/SyncReverseProxy/ResumableTests.cs index 3c121f5a4..32593b1f9 100644 --- a/backend/Testing/SyncReverseProxy/ResumableTests.cs +++ b/backend/Testing/SyncReverseProxy/ResumableTests.cs @@ -2,7 +2,7 @@ using System.Net; using System.Net.Http.Headers; using System.Text; -using Shouldly; +using FluentAssertions; using Testing.ApiTests; using Testing.Services; @@ -28,10 +28,10 @@ public async Task IsAvailable(string user) } }, HttpCompletionOption.ResponseHeadersRead); var responseString = await responseMessage.Content.ReadAsStringAsync(); - responseString.ShouldBeNullOrEmpty(); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); + responseString.Should().BeNullOrEmpty(); + responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); var headers = responseMessage.Headers.ToDictionary(kvp => kvp.Key, kvp => string.Join(',', kvp.Value), StringComparer.OrdinalIgnoreCase); - headers.ShouldContainKeyAndValue("X-HgR-Version", "3"); + headers.Should().Contain("X-HgR-Version", "3"); } [Theory] @@ -40,7 +40,7 @@ public async Task IsAvailable(string user) public async Task IsAvailableJwtInBasicAuth(string user) { var jwt = await JwtHelper.GetJwtForUser(new(user, TestData.Password)); - jwt.ShouldNotBeNullOrEmpty(); + jwt.Should().NotBeNullOrEmpty(); var responseMessage = await Client.SendAsync(new(HttpMethod.Get, $"{_baseUrl}/api/v03/isAvailable?repoId={TestingEnvironmentVariables.ProjectCode}") @@ -51,10 +51,10 @@ public async Task IsAvailableJwtInBasicAuth(string user) } }, HttpCompletionOption.ResponseHeadersRead); var responseString = await responseMessage.Content.ReadAsStringAsync(); - responseString.ShouldBeNullOrEmpty(); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); + responseString.Should().BeNullOrEmpty(); + responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); var headers = responseMessage.Headers.ToDictionary(kvp => kvp.Key, kvp => string.Join(',', kvp.Value), StringComparer.OrdinalIgnoreCase); - headers.ShouldContainKeyAndValue("X-HgR-Version", "3"); + headers.Should().Contain("X-HgR-Version", "3"); } [Fact] @@ -69,7 +69,7 @@ public async Task WithBadUser() Convert.ToBase64String(Encoding.ASCII.GetBytes($"not a user:doesnt matter"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } [Fact] @@ -84,7 +84,7 @@ public async Task WithBadPassword() Convert.ToBase64String(Encoding.ASCII.GetBytes($"{TestData.User}:wrong password"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } [Fact] @@ -99,7 +99,7 @@ public async Task WithBadNotValidProject() Convert.ToBase64String(Encoding.ASCII.GetBytes($"{TestData.User}:{TestData.Password}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } [Fact] @@ -115,6 +115,6 @@ public async Task WithUnauthorizedUser() Convert.ToBase64String(Encoding.ASCII.GetBytes($"{userWithoutPermission}:{TestData.Password}"))) } }); - responseMessage.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); + responseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } } diff --git a/backend/Testing/SyncReverseProxy/SendReceiveServiceTests.cs b/backend/Testing/SyncReverseProxy/SendReceiveServiceTests.cs index be5dd69d3..8d6edc151 100644 --- a/backend/Testing/SyncReverseProxy/SendReceiveServiceTests.cs +++ b/backend/Testing/SyncReverseProxy/SendReceiveServiceTests.cs @@ -1,6 +1,6 @@ using Chorus.VcsDrivers.Mercurial; using LexBoxApi.Auth; -using Shouldly; +using FluentAssertions; using SIL.Progress; using System.Net.Http.Json; using System.Text.Json.Nodes; @@ -35,10 +35,10 @@ public SendReceiveServiceTests(ITestOutputHelper output, IntegrationFixture send public async Task VerifyHgWorking() { var version = await _sendReceiveService.GetHgVersion(); - version.ShouldStartWith("Mercurial Distributed SCM"); + version.Should().StartWith("Mercurial Distributed SCM"); _output.WriteLine("Hg version: " + version); HgRunner.Run("hg version", Environment.CurrentDirectory, 5, new XunitStringBuilderProgress(_output) { ShowVerbose = true }); - HgRepository.GetEnvironmentReadinessMessage("en").ShouldBeNull(); + HgRepository.GetEnvironmentReadinessMessage("en").Should().BeNull(); } [Theory] @@ -65,7 +65,7 @@ public async Task CloneConfidentialProjectAsOrgManager(HgProtocol protocol) // Verify pushed var lastCommitDate = await _adminApiTester.GetProjectLastCommit(projectConfig.Code); - lastCommitDate.ShouldNotBeNullOrEmpty(); + lastCommitDate.Should().NotBeNull(); } [Theory] @@ -105,11 +105,11 @@ public async Task ModifyProjectData(HgProtocol protocol) // Verify pushed and store last commit var lastCommitDate = await _adminApiTester.GetProjectLastCommit(projectConfig.Code); - lastCommitDate.ShouldNotBeNullOrEmpty(); + lastCommitDate.Should().NotBeNull(); // Modify var fwDataFileInfo = new FileInfo(sendReceiveParams.FwDataFile); - fwDataFileInfo.Length.ShouldBeGreaterThan(0); + fwDataFileInfo.Length.Should().BeGreaterThan(0); ModifyProjectHelper.ModifyProject(sendReceiveParams.FwDataFile); // Push changes @@ -117,7 +117,7 @@ public async Task ModifyProjectData(HgProtocol protocol) // Verify the push updated the last commit date var lastCommitDateAfter = await _adminApiTester.GetProjectLastCommit(projectConfig.Code); - lastCommitDateAfter.ShouldBeGreaterThan(lastCommitDate); + lastCommitDateAfter.Should().BeAfter(lastCommitDate.Value); } [Theory] @@ -137,7 +137,7 @@ public async Task SendReceiveAfterProjectReset(HgProtocol protocol) var response = await _adminApiTester.HttpClient.GetAsync(tipUri); var jsonResult = await response.Content.ReadFromJsonAsync(); var originalTip = jsonResult?["node"]?.AsValue()?.ToString(); - originalTip.ShouldNotBeNull(); + originalTip.Should().NotBeNull(); // /api/project/resetProject/{code} // /api/project/finishResetProject/{code} // leave project empty @@ -152,9 +152,8 @@ public async Task SendReceiveAfterProjectReset(HgProtocol protocol) response = await _adminApiTester.HttpClient.GetAsync(tipUri); jsonResult = await response.Content.ReadFromJsonAsync(); var emptyTip = jsonResult?["node"]?.AsValue()?.ToString(); - emptyTip.ShouldNotBeNull(); - emptyTip.ShouldNotBeEmpty(); - emptyTip.Replace("0", "").ShouldBeEmpty(); + emptyTip.Should().NotBeNullOrEmpty(); + emptyTip.Replace("0", "").Should().BeEmpty(); // Step 3: do Send/Receive if (protocol == HgProtocol.Resumable) @@ -175,8 +174,8 @@ public async Task SendReceiveAfterProjectReset(HgProtocol protocol) response = await _adminApiTester.HttpClient.GetAsync(tipUri); jsonResult = await response.Content.ReadFromJsonAsync(); var postSRTip = jsonResult?["node"]?.AsValue()?.ToString(); - postSRTip.ShouldNotBeNull(); - postSRTip.ShouldBe(originalTip); + postSRTip.Should().NotBeNull(); + postSRTip.Should().Be(originalTip); } [Fact] @@ -207,7 +206,7 @@ private async Task SendNewProject(int totalSizeMb, int fileCount) var fileName = $"test-file{i}.bin"; WriteFile(Path.Combine(sendReceiveParams.Dir, fileName), totalSizeMb / fileCount); HgRunner.Run($"hg add {fileName}", sendReceiveParams.Dir, 5, progress); - HgRunner.Run($"""hg commit -m "large file commit {i}" """, sendReceiveParams.Dir, 5, progress).ExitCode.ShouldBe(0); + HgRunner.Run($"""hg commit -m "large file commit {i}" """, sendReceiveParams.Dir, 5, progress).ExitCode.Should().Be(0); } var srResult = _sendReceiveService.SendReceiveProject(sendReceiveParams, AdminAuth); @@ -235,7 +234,7 @@ public void InvalidPassOnCloneHgWeb() var sendReceiveParams = GetParams(HgProtocol.Hgweb); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, InvalidPass); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -244,7 +243,7 @@ public void InvalidPassOnCloneHgResumable() var sendReceiveParams = GetParams(HgProtocol.Resumable); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, InvalidPass); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -254,7 +253,7 @@ public void InvalidPassOnSendReceiveHgWeb() _sendReceiveService.CloneProject(sendReceiveParams, ManagerAuth); var act = () => _sendReceiveService.SendReceiveProject(sendReceiveParams, InvalidPass); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -264,7 +263,7 @@ public void InvalidPassOnSendReceiveHgResumable() _sendReceiveService.CloneProject(sendReceiveParams, ManagerAuth); var act = () => _sendReceiveService.SendReceiveProject(sendReceiveParams, InvalidPass); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -272,7 +271,7 @@ public void InvalidUserCloneHgWeb() { var sendReceiveParams = GetParams(HgProtocol.Hgweb); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, InvalidUser); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -280,7 +279,7 @@ public void InvalidUserCloneHgResumable() { var sendReceiveParams = GetParams(HgProtocol.Resumable); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, InvalidUser); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -289,8 +288,8 @@ public void InvalidProjectAdminLogin() var sendReceiveParams = GetParams(HgProtocol.Hgweb, "non-existent-project"); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, AdminAuth); - act.ShouldThrow(); - Directory.GetFiles(sendReceiveParams.Dir).ShouldBeEmpty(); + act.Should().Throw(); + Directory.GetFiles(sendReceiveParams.Dir).Should().BeEmpty(); } [Fact] @@ -299,8 +298,8 @@ public void InvalidProjectManagerLogin() var sendReceiveParams = GetParams(HgProtocol.Hgweb, "non-existent-project"); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, ManagerAuth); - act.ShouldThrow(); - Directory.GetFiles(sendReceiveParams.Dir).ShouldBeEmpty(); + act.Should().Throw(); + Directory.GetFiles(sendReceiveParams.Dir).Should().BeEmpty(); } [Fact] @@ -309,7 +308,7 @@ public void UnauthorizedUserCloneHgWeb() var sendReceiveParams = GetParams(HgProtocol.Hgweb); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, UnauthorizedUser); - act.ShouldThrow(); + act.Should().Throw(); } [Fact] @@ -318,6 +317,6 @@ public void UnauthorizedUserCloneHgResumable() var sendReceiveParams = GetParams(HgProtocol.Resumable); var act = () => _sendReceiveService.CloneProject(sendReceiveParams, UnauthorizedUser); - act.ShouldThrow(); + act.Should().Throw(); } } diff --git a/backend/Testing/Testing.csproj b/backend/Testing/Testing.csproj index 04fa2ae8c..3ccb8771e 100644 --- a/backend/Testing/Testing.csproj +++ b/backend/Testing/Testing.csproj @@ -36,7 +36,7 @@ - + diff --git a/backend/Testing/Usings.cs b/backend/Testing/Usings.cs index 8c927eb74..c802f4480 100644 --- a/backend/Testing/Usings.cs +++ b/backend/Testing/Usings.cs @@ -1 +1 @@ -global using Xunit; \ No newline at end of file +global using Xunit;