Skip to content

Commit 3dbadf9

Browse files
myieyeclaude
andcommitted
Run the main-publication invariant tests on FwData too
The single-main guards are enforced in the backend-agnostic validation wrapper, so move them to PublicationsTestsBase. FwData maps IsMain from the read-only IsProtected, so the FwData test seeds a main at the LCM layer. The promotion and merge-convergence tests stay CRDT-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c1a22dd commit 3dbadf9

3 files changed

Lines changed: 53 additions & 31 deletions

File tree

backend/FwLite/FwDataMiniLcmBridge.Tests/MiniLcmTests/PublicationsTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using FwDataMiniLcmBridge.Api;
12
using FwDataMiniLcmBridge.Tests.Fixtures;
3+
using MiniLcm.Models;
4+
using SIL.LCModel.Infrastructure;
25

36
namespace FwDataMiniLcmBridge.Tests.MiniLcmTests;
47

@@ -9,4 +12,17 @@ protected override Task<IMiniLcmApi> NewApi()
912
{
1013
return Task.FromResult<IMiniLcmApi>(fixture.NewProjectApi("publications-test", "en", "en"));
1114
}
15+
16+
// FieldWorks' main publication is its protected one; the MiniLcm write path deliberately never flips
17+
// IsProtected (see UpdatePublicationProxy), so seed it directly at the LCM layer for these tests.
18+
protected override async Task<Publication> SeedMainPublication(string name = "Main")
19+
{
20+
var fwApi = (FwDataMiniLcmApi)BaseApi;
21+
var pub = await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", name } } });
22+
var lcmPublication = fwApi.GetLcmPublication(pub.Id)
23+
?? throw new InvalidOperationException($"Seeded publication {pub.Id} not found in LCM");
24+
NonUndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW(fwApi.Cache.ServiceLocator.ActionHandler,
25+
() => lcmPublication.IsProtected = true);
26+
return await Api.GetPublication(pub.Id) ?? throw new InvalidOperationException($"Seeded main {pub.Id} not found");
27+
}
1228
}

backend/FwLite/LcmCrdt.Tests/MiniLcmTests/PublicationsTests.cs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,6 @@ public override async Task DisposeAsync()
2020
await _fixture.DisposeAsync();
2121
}
2222

23-
[Fact]
24-
public async Task UpdatePublication_CannotTurnOffIsMain()
25-
{
26-
var main = await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Main" } }, IsMain = true });
27-
28-
var act = () => Api.UpdatePublication(main.Id, new UpdateObjectInput<Publication>().Set(p => p.IsMain, false));
29-
30-
await act.Should().ThrowAsync<FluentValidation.ValidationException>();
31-
}
32-
33-
[Fact]
34-
public async Task UpdatePublication_CannotPromoteSecondMain()
35-
{
36-
await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Main" } }, IsMain = true });
37-
var other = await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Pocket" } } });
38-
39-
var act = () => Api.UpdatePublication(other.Id, new UpdateObjectInput<Publication>().Set(p => p.IsMain, true));
40-
41-
await act.Should().ThrowAsync<InvalidOperationException>();
42-
}
43-
44-
[Fact]
45-
public async Task CreatePublication_CannotCreateSecondMain()
46-
{
47-
await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Main" } }, IsMain = true });
48-
49-
var act = () => Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Second" } }, IsMain = true });
50-
51-
await act.Should().ThrowAsync<InvalidOperationException>();
52-
}
53-
5423
[Fact]
5524
public async Task PublicationSync_PromotesExistingPublicationToMain()
5625
{

backend/FwLite/MiniLcm.Tests/PublicationsTestsBase.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,41 @@ public async Task UpdatePublication_WithBeforeAndAfter_Works()
110110
var actualPub = await Api.UpdatePublication(publication, afterPub);
111111
actualPub.Should().BeEquivalentTo(afterPub);
112112
}
113+
114+
/// <summary>Creates the project's single main publication. Overridden per backend (e.g. FwData maps it to a protected publication).</summary>
115+
protected virtual async Task<Publication> SeedMainPublication(string name = "Main")
116+
{
117+
return await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", name } }, IsMain = true });
118+
}
119+
120+
[Fact]
121+
public async Task CreatePublication_CannotCreateSecondMain()
122+
{
123+
await SeedMainPublication();
124+
125+
var act = () => Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Second" } }, IsMain = true });
126+
127+
await act.Should().ThrowAsync<InvalidOperationException>();
128+
}
129+
130+
[Fact]
131+
public async Task UpdatePublication_CannotPromoteSecondMain()
132+
{
133+
await SeedMainPublication();
134+
var other = await Api.CreatePublication(new Publication { Id = Guid.NewGuid(), Name = { { "en", "Pocket" } } });
135+
136+
var act = () => Api.UpdatePublication(other.Id, new UpdateObjectInput<Publication>().Set(p => p.IsMain, true));
137+
138+
await act.Should().ThrowAsync<InvalidOperationException>();
139+
}
140+
141+
[Fact]
142+
public async Task UpdatePublication_CannotTurnOffIsMain()
143+
{
144+
var main = await SeedMainPublication();
145+
146+
var act = () => Api.UpdatePublication(main.Id, new UpdateObjectInput<Publication>().Set(p => p.IsMain, false));
147+
148+
await act.Should().ThrowAsync<FluentValidation.ValidationException>();
149+
}
113150
}

0 commit comments

Comments
 (0)