Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

189 строки
6.5KB

  1. using Campaign_Tracker.Server.ExtensionData;
  2. using Campaign_Tracker.Server.LegacyData;
  3. using Campaign_Tracker.Server.LegacyData.Models;
  4. using Campaign_Tracker.Server.Municipalities;
  5. namespace Campaign_Tracker.Server.Tests;
  6. public sealed class MunicipalityProfileRepositoryTests
  7. {
  8. private static readonly DateTimeOffset FixedNow =
  9. new(2026, 5, 6, 12, 0, 0, TimeSpan.Zero);
  10. private static InMemoryMunicipalityProfileRepository BuildSut(
  11. ILegacyDataAccess? data = null)
  12. {
  13. data ??= new InMemoryLegacyDataAccess(
  14. jurisdictions:
  15. [
  16. new("FAIR01", "Fairview Borough", "100 Main St", "Fairview, PA 16415", null, null),
  17. new("LAKE02", "Lake Township", "200 Lake Rd", "Lake City, PA 16423", null, null),
  18. ]);
  19. return new InMemoryMunicipalityProfileRepository(
  20. new LegacyLinkValidator(data),
  21. data,
  22. new FakeTimeProvider(FixedNow));
  23. }
  24. // ── AC #1: profile saved with required JCode link ────────────────────────
  25. [Fact]
  26. public async Task CreateAsync_ValidJCode_SavesProfileWithLegacyLink_AC1()
  27. {
  28. var sut = BuildSut();
  29. var result = await sut.CreateAsync("FAIR01", "Fairview Profile", "user@test.com");
  30. Assert.True(result.Saved);
  31. Assert.NotNull(result.Profile);
  32. Assert.Equal("FAIR01", result.Profile.JCode);
  33. Assert.Equal("MunicipalityProfile", result.Profile.RecordType);
  34. Assert.Equal(LegacyLinkType.JurisdictionJCode, result.Profile.LegacyLink.Type);
  35. Assert.Equal("FAIR01", result.Profile.LegacyLink.Value);
  36. }
  37. [Fact]
  38. public async Task CreateAsync_ProfileIdIsGeneratedGuid_AC1()
  39. {
  40. var sut = BuildSut();
  41. var result = await sut.CreateAsync("FAIR01", null, "user@test.com");
  42. Assert.NotNull(result.Profile);
  43. Assert.True(Guid.TryParse(result.Profile.ProfileId, out _), "ProfileId should be a valid GUID.");
  44. }
  45. // ── AC #2: combined view resolves legacy jurisdiction data ────────────────
  46. [Fact]
  47. public async Task GetAllAsync_ReturnsLegacyJurisdictionFieldsAlongsideExtensionData_AC2()
  48. {
  49. var sut = BuildSut();
  50. await sut.CreateAsync("FAIR01", "Fairview Display", "user@test.com");
  51. var views = await sut.GetAllAsync();
  52. Assert.Single(views);
  53. var view = views[0];
  54. Assert.Equal("FAIR01", view.Profile.JCode);
  55. Assert.Equal("Fairview Borough", view.LegacyName);
  56. Assert.Equal("100 Main St", view.LegacyMailingAddress);
  57. Assert.Equal("Fairview, PA 16415", view.LegacyCityStateZip);
  58. }
  59. [Fact]
  60. public async Task GetByIdAsync_ReturnsLegacyAndExtensionDataCombined_AC2()
  61. {
  62. var sut = BuildSut();
  63. var created = await sut.CreateAsync("LAKE02", null, "user@test.com");
  64. var view = await sut.GetByIdAsync(created.Profile!.ProfileId);
  65. Assert.NotNull(view);
  66. Assert.Equal("LAKE02", view.Profile.JCode);
  67. Assert.Equal("Lake Township", view.LegacyName);
  68. }
  69. [Fact]
  70. public async Task GetByIdAsync_UnknownId_ReturnsNull_AC2()
  71. {
  72. var sut = BuildSut();
  73. var view = await sut.GetByIdAsync("does-not-exist");
  74. Assert.Null(view);
  75. }
  76. // ── AC #3: update records actor and timestamp ─────────────────────────────
  77. [Fact]
  78. public async Task UpdateAsync_ChangesDisplayNameAndCapturesActor_AC3()
  79. {
  80. var sut = BuildSut();
  81. var created = await sut.CreateAsync("FAIR01", "Old Name", "creator@test.com");
  82. var updated = await sut.UpdateAsync(created.Profile!.ProfileId, "New Name", "updater@test.com");
  83. Assert.True(updated.Saved);
  84. Assert.Equal("New Name", updated.Profile!.DisplayName);
  85. Assert.Equal("updater@test.com", updated.Profile.UpdatedBy);
  86. Assert.Equal(FixedNow, updated.Profile.UpdatedAt);
  87. }
  88. [Fact]
  89. public async Task UpdateAsync_UnknownId_ReturnsFailure_AC3()
  90. {
  91. var sut = BuildSut();
  92. var result = await sut.UpdateAsync("ghost-id", "name", "actor");
  93. Assert.False(result.Saved);
  94. Assert.Contains("ghost-id", result.Error);
  95. }
  96. // ── AC #4: invalid JCode rejected before save ─────────────────────────────
  97. [Fact]
  98. public async Task CreateAsync_InvalidJCode_ReturnsFailureWithDescription_AC4()
  99. {
  100. var sut = BuildSut(new InMemoryLegacyDataAccess(jurisdictions: []));
  101. var result = await sut.CreateAsync("UNKNOWN", null, "user@test.com");
  102. Assert.False(result.Saved);
  103. Assert.NotNull(result.Error);
  104. Assert.Contains("UNKNOWN", result.Error);
  105. }
  106. [Fact]
  107. public async Task CreateAsync_BlankJCode_ReturnsFailureWithDescription_AC4()
  108. {
  109. var sut = BuildSut();
  110. var result = await sut.CreateAsync("", null, "user@test.com");
  111. Assert.False(result.Saved);
  112. Assert.NotNull(result.Error);
  113. }
  114. [Fact]
  115. public async Task CreateAsync_DuplicateJCode_ReturnsFailure_AC4()
  116. {
  117. var sut = BuildSut();
  118. await sut.CreateAsync("FAIR01", null, "user@test.com");
  119. var second = await sut.CreateAsync("FAIR01", "Another", "user@test.com");
  120. Assert.False(second.Saved);
  121. Assert.Contains("FAIR01", second.Error);
  122. }
  123. // ── ILegacyLinkedRecordProvider participates in integrity check ──────────
  124. [Fact]
  125. public async Task GetAllAsync_AsLinkedRecordProvider_ReturnsProfilesForIntegrityCheck_AC1()
  126. {
  127. var sut = BuildSut();
  128. await sut.CreateAsync("FAIR01", null, "user@test.com");
  129. await sut.CreateAsync("LAKE02", null, "user@test.com");
  130. var provider = (ILegacyLinkedRecordProvider)sut;
  131. var records = await provider.GetAllAsync();
  132. Assert.Equal(2, records.Count);
  133. Assert.All(records, r =>
  134. {
  135. Assert.Equal("MunicipalityProfile", r.RecordType);
  136. Assert.Equal(LegacyLinkType.JurisdictionJCode, r.LegacyLink.Type);
  137. });
  138. }
  139. // ── Helpers ───────────────────────────────────────────────────────────────
  140. private sealed class FakeTimeProvider(DateTimeOffset utcNow) : TimeProvider
  141. {
  142. public override DateTimeOffset GetUtcNow() => utcNow;
  143. }
  144. }

Powered by TurnKey Linux.