diff --git a/SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs b/SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs index 30aaf57..026e57b 100644 --- a/SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs +++ b/SharepointToolbox.Tests/Services/Export/UserAccessHtmlExportServiceTests.cs @@ -141,4 +141,97 @@ public class UserAccessHtmlExportServiceTests var html = svc.BuildHtml(new[] { DefaultEntry }, MakeBranding(msp: true)); Assert.Contains("data:image/png;base64,bXNw", html); } + + // ── Consolidation tests (RPT-03-b through RPT-03-e) ────────────────────── + + // Shared test data: 3 entries where 2 share the same consolidation key + private static IReadOnlyList MakeConsolidationTestEntries() + { + // Entry 1 + Entry 2: same user/permission/accesstype/grantedthrough, different sites + var e1 = MakeEntry( + userDisplay: "Bob Jones", + userLogin: "bob@contoso.com", + siteUrl: "https://contoso.sharepoint.com/sites/Alpha", + siteTitle: "Alpha Site", + permLevel: "Contribute", + accessType: AccessType.Direct, + grantedThrough: "Direct Permissions"); + + var e2 = MakeEntry( + userDisplay: "Bob Jones", + userLogin: "bob@contoso.com", + siteUrl: "https://contoso.sharepoint.com/sites/Beta", + siteTitle: "Beta Site", + permLevel: "Contribute", + accessType: AccessType.Direct, + grantedThrough: "Direct Permissions"); + + // Entry 3: different user — will have 1 location + var e3 = MakeEntry( + userDisplay: "Carol Davis", + userLogin: "carol@contoso.com", + siteUrl: "https://contoso.sharepoint.com/sites/Gamma", + siteTitle: "Gamma Site", + permLevel: "Read", + accessType: AccessType.Group, + grantedThrough: "Readers Group"); + + return new[] { e1, e2, e3 }; + } + + // RPT-03-b: BuildHtml(entries, mergePermissions: false) is byte-identical to BuildHtml(entries) + [Fact] + public void BuildHtml_mergePermissionsFalse_identical_to_default() + { + var entries = MakeConsolidationTestEntries(); + var svc = new UserAccessHtmlExportService(); + + var defaultOutput = svc.BuildHtml(entries); + var explicitFalse = svc.BuildHtml(entries, mergePermissions: false); + + Assert.Equal(defaultOutput, explicitFalse); + } + + // RPT-03-c: BuildHtml(entries, mergePermissions: true) contains "Sites" column header and consolidated content + [Fact] + public void BuildHtml_mergePermissionsTrue_contains_sites_column() + { + var entries = MakeConsolidationTestEntries(); + var svc = new UserAccessHtmlExportService(); + + var html = svc.BuildHtml(entries, mergePermissions: true); + + Assert.Contains("Sites", html); + // Consolidated rows present for both users + Assert.Contains("Bob Jones", html); + Assert.Contains("Carol Davis", html); + } + + // RPT-03-d: 2+ locations produce [N sites] badge with toggleGroup and hidden sub-rows + [Fact] + public void BuildHtml_mergePermissionsTrue_multiLocation_has_badge_and_subrows() + { + var entries = MakeConsolidationTestEntries(); + var svc = new UserAccessHtmlExportService(); + + var html = svc.BuildHtml(entries, mergePermissions: true); + + // Badge with onclick + Assert.Contains("onclick=\"toggleGroup('loc", html); + // Hidden sub-rows + Assert.Contains("data-group=\"loc", html); + } + + // RPT-03-e: mergePermissions=true omits "By Site" button and view-site div + [Fact] + public void BuildHtml_mergePermissionsTrue_omits_bysite_view() + { + var entries = MakeConsolidationTestEntries(); + var svc = new UserAccessHtmlExportService(); + + var html = svc.BuildHtml(entries, mergePermissions: true); + + Assert.DoesNotContain("btn-site", html); + Assert.DoesNotContain("view-site", html); + } }