using System.Collections.Generic; using SharepointToolbox.Core.Models; using SharepointToolbox.Services.Export; namespace SharepointToolbox.Tests.Services.Export; /// /// Unit tests for UserAccessHtmlExportService (Phase 7 Plan 08). /// Verifies: DOCTYPE, stats cards, dual-view sections, access type badges, /// filter script, toggle script, HTML entity encoding. /// public class UserAccessHtmlExportServiceTests { // ── Helper factory ──────────────────────────────────────────────────────── private static ReportBranding MakeBranding(bool msp = true, bool client = false) { var mspLogo = msp ? new LogoData { Base64 = "bXNw", MimeType = "image/png" } : null; var clientLogo = client ? new LogoData { Base64 = "Y2xpZW50", MimeType = "image/jpeg" } : null; return new ReportBranding(mspLogo, clientLogo); } private static UserAccessEntry MakeEntry( string userDisplay = "Alice Smith", string userLogin = "alice@contoso.com", string siteUrl = "https://contoso.sharepoint.com", string siteTitle = "Contoso", string objectType = "List", string objectTitle = "Docs", string objectUrl = "https://contoso.sharepoint.com/Docs", string permLevel = "Read", AccessType accessType = AccessType.Direct, string grantedThrough = "Direct Permissions", bool isHighPrivilege = false, bool isExternal = false) => new(userDisplay, userLogin, siteUrl, siteTitle, objectType, objectTitle, objectUrl, permLevel, accessType, grantedThrough, isHighPrivilege, isExternal); private static readonly UserAccessEntry DefaultEntry = MakeEntry(); // ── Test 1: BuildHtml contains DOCTYPE ─────────────────────────────────── [Fact] public void BuildHtml_contains_doctype() { var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { DefaultEntry }); Assert.StartsWith("", html.TrimStart()); } // ── Test 2: BuildHtml has stats cards ───────────────────────────────────── [Fact] public void BuildHtml_has_stats_cards() { var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { DefaultEntry }); Assert.Contains("Total Accesses", html); Assert.Contains("stat-card", html); } // ── Test 3: BuildHtml has both view sections ────────────────────────────── [Fact] public void BuildHtml_has_both_views() { var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { DefaultEntry }); // By-user view Assert.Contains("view-user", html); // By-site view Assert.Contains("view-site", html); } // ── Test 4: BuildHtml has access type badge CSS classes ─────────────────── [Fact] public void BuildHtml_has_access_type_badges() { var entries = new List { MakeEntry(accessType: AccessType.Direct), MakeEntry(userLogin: "bob@contoso.com", accessType: AccessType.Group), MakeEntry(userLogin: "carol@contoso.com", accessType: AccessType.Inherited) }; var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(entries); Assert.Contains("access-direct", html); Assert.Contains("access-group", html); Assert.Contains("access-inherited", html); } // ── Test 5: BuildHtml has filterTable JS function ───────────────────────── [Fact] public void BuildHtml_has_filter_script() { var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { DefaultEntry }); Assert.Contains("filterTable", html); } // ── Test 6: BuildHtml has toggleView JS function ────────────────────────── [Fact] public void BuildHtml_has_toggle_script() { var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { DefaultEntry }); Assert.Contains("toggleView", html); } // ── Test 7: BuildHtml encodes HTML entities ─────────────────────────────── [Fact] public void BuildHtml_encodes_html_entities() { var entryWithScript = MakeEntry(objectTitle: ""); var svc = new UserAccessHtmlExportService(); var html = svc.BuildHtml(new[] { entryWithScript }); // Raw script tag must not appear verbatim Assert.DoesNotContain("