@@ -13,6 +13,69 @@ Describe "Testing Health Checker by Mock Data Imports" {
1313 . $PSScriptRoot \HealthCheckerTest.CommonMocks.NotPublished.ps1
1414 }
1515
16+ Context " GetHtmlTextValue Unit Tests" {
17+
18+ It " Should return null for null input" {
19+ $result = GetHtmlTextValue - OriginalValue $null
20+ $result | Should - BeNullOrEmpty
21+ }
22+
23+ It " Should return empty string for empty input" {
24+ $result = GetHtmlTextValue - OriginalValue " "
25+ $result | Should - Be " "
26+ }
27+
28+ It " Should return plain text unchanged" {
29+ $result = GetHtmlTextValue - OriginalValue " Exchange 2019 CU11"
30+ $result | Should - Be " Exchange 2019 CU11"
31+ }
32+
33+ It " Should encode angle brackets for certificate SAN values" {
34+ $result = GetHtmlTextValue - OriginalValue " <SAN>CN=mail.contoso.com</SAN>"
35+ $result | Should - Be " <SAN>CN=mail.contoso.com</SAN>"
36+ }
37+
38+ It " Should encode greater-than sign" {
39+ $result = GetHtmlTextValue - OriginalValue " Value > 100"
40+ $result | Should - Be " Value > 100"
41+ }
42+
43+ It " Should encode less-than sign" {
44+ $result = GetHtmlTextValue - OriginalValue " Value < 100"
45+ $result | Should - Be " Value < 100"
46+ }
47+
48+ It " Should handle mixed content with angle brackets and normal text" {
49+ $result = GetHtmlTextValue - OriginalValue " Status: <Unknown> - Check docs"
50+ $result | Should - Be " Status: <Unknown> - Check docs"
51+ }
52+
53+ It " Should preserve intentional br tags after encoding" {
54+ $testValue = " CVE-2020-1147<br>CVE-2023-36434<br>"
55+ $result = GetHtmlTextValue - OriginalValue $testValue
56+ $result | Should - Be " CVE-2020-1147<br>CVE-2023-36434<br>"
57+ }
58+
59+ It " Should convert URLs to clickable hyperlinks" {
60+ $result = GetHtmlTextValue - OriginalValue " More Information: https://aka.ms/HC-ExBuilds"
61+ # cspell:ignore noopener noreferrer
62+ $result | Should - BeLike ' *<a href="https://aka.ms/HC-ExBuilds"*>https://aka.ms/HC-ExBuilds</a>'
63+ }
64+
65+ It " Should convert URLs with trailing sentence punctuation" {
66+ $result = GetHtmlTextValue - OriginalValue " See: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2020-1147 for more information."
67+ $result | Should - BeLike ' *<a href=*>https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2020-1147</a> for more information.'
68+ }
69+
70+ It " Should handle br tags combined with URLs in security vulnerability summary" {
71+ $testValue = " CVE-2020-1147`r`n`t`t See: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2020-1147 for more information.<br>"
72+ $result = GetHtmlTextValue - OriginalValue $testValue
73+ $result | Should - BeLike " *<br>*"
74+ $result | Should -Not - BeLike " *<br>*"
75+ $result | Should - BeLike " *<a href=*>*</a>*"
76+ }
77+ }
78+
1679 Context " Basic Exchange 2019 CU11 Testing HyperV" {
1780 BeforeAll {
1881 SetDefaultRunOfHealthChecker " Debug_HyperV_Results.xml"
@@ -192,6 +255,80 @@ Describe "Testing Health Checker by Mock Data Imports" {
192255 $globalRulesWarning = GetObject " Global IIS Rewrite Rules"
193256 $globalRulesWarning | Should -Not - BeNullOrEmpty
194257 }
258+
259+ It " HTML Report - HtmlServerValues Structure" {
260+ $Script :results.HtmlServerValues.ContainsKey (" ServerDetails" ) | Should - Be $true
261+ $Script :results.HtmlServerValues.ContainsKey (" OverviewValues" ) | Should - Be $true
262+ $Script :results.HtmlServerValues [" ServerDetails" ].Count | Should - BeGreaterThan 0
263+ $Script :results.HtmlServerValues [" OverviewValues" ].Count | Should - BeGreaterThan 0
264+
265+ $firstDetail = $Script :results.HtmlServerValues [" ServerDetails" ][0 ]
266+ $firstDetail.PSObject.Properties.Name | Should - Contain " Name"
267+ $firstDetail.PSObject.Properties.Name | Should - Contain " DetailValue"
268+ $firstDetail.PSObject.Properties.Name | Should - Contain " TableValue"
269+ $firstDetail.PSObject.Properties.Name | Should - Contain " Class"
270+
271+ $firstOverview = $Script :results.HtmlServerValues [" OverviewValues" ][0 ]
272+ $firstOverview.PSObject.Properties.Name | Should - Contain " Name"
273+ $firstOverview.PSObject.Properties.Name | Should - Contain " DetailValue"
274+
275+ # ServerDetails captures most entries while OverviewValues is selective
276+ $Script :results.HtmlServerValues [" ServerDetails" ].Count |
277+ Should - BeGreaterThan $Script :results.HtmlServerValues [" OverviewValues" ].Count
278+ }
279+
280+ It " HTML Report - Overview Values" {
281+ $serverName = GetHtmlOverviewValue " Server Name"
282+ $serverName | Should -Not - BeNullOrEmpty
283+ $serverName.DetailValue | Should -Not - BeNullOrEmpty
284+
285+ $exchangeVersion = GetHtmlOverviewValue " Exchange Version"
286+ $exchangeVersion | Should -Not - BeNullOrEmpty
287+ $exchangeVersion.DetailValue | Should -Not - BeNullOrEmpty
288+
289+ $generationTime = GetHtmlOverviewValue " Generation Time"
290+ $generationTime | Should -Not - BeNullOrEmpty
291+
292+ $vulnDetected = GetHtmlOverviewValue " Vulnerability Detected"
293+ $vulnDetected | Should -Not - BeNullOrEmpty
294+ if ($vulnDetected.DetailValue -ne " None" ) {
295+ $vulnDetected.Class | Should - Be " Red"
296+ }
297+ }
298+
299+ It " HTML Report - ServerDetails CSS Class Mapping" {
300+ # Grey write type → empty Class
301+ $serverName = GetHtmlServerDetail " Server Name"
302+ $serverName | Should -Not - BeNullOrEmpty
303+ $serverName.Class | Should - BeNullOrEmpty
304+
305+ # Yellow write type → Yellow Class
306+ $edition = GetHtmlServerDetail " Edition"
307+ if ($null -ne $edition ) {
308+ $edition.Class | Should - Be " Yellow"
309+ }
310+ }
311+
312+ It " HTML Report - Security Vulnerabilities HTML Rendering" {
313+ # Individual "Security Vulnerability" entries should NOT appear in ServerDetails.
314+ # They are rolled up into the "Security Vulnerabilities" summary row.
315+ # The regular CVE path sets AddHtmlDetailRow = $false, but the override CVE path
316+ # in Invoke-AnalyzerSecurityCveAndOverrideCheck.ps1 is missing it.
317+ $individualCveEntries = $Script :results.HtmlServerValues [" ServerDetails" ] |
318+ Where-Object { $_.Name -eq " Security Vulnerability" }
319+ $individualCveEntries | Should - BeNullOrEmpty
320+
321+ # The summary row should be present
322+ $entry = GetHtmlServerDetail " Security Vulnerabilities"
323+ $entry | Should -Not - BeNullOrEmpty
324+
325+ if ($null -ne $entry -and -not [string ]::IsNullOrEmpty($entry.DetailValue )) {
326+ $entry.DetailValue | Should - BeLike " *CVE-*"
327+ # Validates the fix for the PR #2475 regression: <br> tags must be preserved
328+ $entry.DetailValue | Should -Not - BeLike " *<br>*"
329+ $entry.DetailValue | Should - BeLike " *<br>*"
330+ }
331+ }
195332 }
196333
197334 Context " Basic Exchange 2019 CU11 Testing Physical" {
0 commit comments