From e3fd6dbb43b9fa5683e4bdab355feef7e142d23a Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Mon, 23 Feb 2026 10:42:09 +0100 Subject: [PATCH 1/2] Fix double HTML encoding in /diff view DiffView.razor was calling HtmlEncode() on line content before passing it to Blazor's @() expression, which already HTML-encodes output. This caused characters like <, >, and " to appear as <, >, " in the diff viewer. Fix: Remove the explicit HtmlEncode() call and let Blazor handle encoding natively. Add regression tests verifying the parser preserves raw HTML characters. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- PolyPilot.Tests/DiffParserTests.cs | 45 +++++++++++++++++++++++++++++ PolyPilot/Components/DiffView.razor | 8 ++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/PolyPilot.Tests/DiffParserTests.cs b/PolyPilot.Tests/DiffParserTests.cs index 4ad3053de7..7b76fa853a 100644 --- a/PolyPilot.Tests/DiffParserTests.cs +++ b/PolyPilot.Tests/DiffParserTests.cs @@ -144,4 +144,49 @@ public void Parse_MultipleFiles_ParsesAll() Assert.Equal("a.cs", files[0].FileName); Assert.Equal("b.cs", files[1].FileName); } + + [Fact] + public void Parse_SpecialHtmlCharacters_PreservedInContent() + { + // Regression: DiffView was double-encoding HTML entities because + // it called HtmlEncode() before passing to Blazor's @() which + // encodes again. Verify the parser preserves raw characters. + var diff = """ + diff --git a/template.html b/template.html + --- a/template.html + +++ b/template.html + @@ -1,3 +1,3 @@ +
+ - old & value + + new & value +
+ """; + var files = DiffParser.Parse(diff); + var lines = files[0].Hunks[0].Lines; + + // Content must contain raw <, >, ", & — no HTML encoding at parse time + Assert.Equal("
", lines[0].Content); + Assert.Equal(" old & value", lines[1].Content); + Assert.Equal(" new & value", lines[2].Content); + Assert.Equal("
", lines[3].Content); + } + + [Fact] + public void Parse_AngleBracketsInCode_NotEncoded() + { + // Verify generic type parameters with <> are preserved as-is + var diff = """ + diff --git a/f.cs b/f.cs + --- a/f.cs + +++ b/f.cs + @@ -1,2 +1,2 @@ + -List items = new List(); + +Dictionary items = new Dictionary(); + """; + var files = DiffParser.Parse(diff); + var lines = files[0].Hunks[0].Lines; + + Assert.Equal("List items = new List();", lines[0].Content); + Assert.Equal("Dictionary items = new Dictionary();", lines[1].Content); + } } diff --git a/PolyPilot/Components/DiffView.razor b/PolyPilot/Components/DiffView.razor index 60a9edfd02..2685b9bb4e 100644 --- a/PolyPilot/Components/DiffView.razor +++ b/PolyPilot/Components/DiffView.razor @@ -1,5 +1,4 @@ @using PolyPilot.Models -@using System.Web @if (Files.Count == 0) { @@ -48,9 +47,9 @@ else { @(row.Left?.OldLineNo?.ToString() ?? "") -
@(row.Left != null ? HtmlEncode(row.Left.Content) : "")
+
@(row.Left?.Content ?? "")
@(row.Right?.NewLineNo?.ToString() ?? "") -
@(row.Right != null ? HtmlEncode(row.Right.Content) : "")
+
@(row.Right?.Content ?? "")
} } @@ -70,7 +69,4 @@ else { Files = DiffParser.Parse(RawDiff); } - - private static string HtmlEncode(string s) => - System.Web.HttpUtility.HtmlEncode(s); } From bd22e5a6fcbe321d3b3f705e12489041faebe84c Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Mon, 23 Feb 2026 10:18:45 -0600 Subject: [PATCH 2/2] Remove stale System.Web import from DiffParser; clarify test comments - Remove unused `using System.Web;` from DiffParser.cs (the HtmlEncode call it supported was in DiffView.razor, not the parser) - Update misleading test comments: tests validate that DiffParser preserves raw characters (a parser invariant), not the DiffView render path where the double-encoding bug lived Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- PolyPilot.Tests/DiffParserTests.cs | 8 ++++---- PolyPilot/Models/DiffParser.cs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/PolyPilot.Tests/DiffParserTests.cs b/PolyPilot.Tests/DiffParserTests.cs index 7b76fa853a..9e0553f182 100644 --- a/PolyPilot.Tests/DiffParserTests.cs +++ b/PolyPilot.Tests/DiffParserTests.cs @@ -148,9 +148,9 @@ public void Parse_MultipleFiles_ParsesAll() [Fact] public void Parse_SpecialHtmlCharacters_PreservedInContent() { - // Regression: DiffView was double-encoding HTML entities because - // it called HtmlEncode() before passing to Blazor's @() which - // encodes again. Verify the parser preserves raw characters. + // Verify the parser preserves raw HTML characters as-is. + // DiffView relies on Blazor's @() auto-encoding, so the parser + // must never pre-encode content. var diff = """ diff --git a/template.html b/template.html --- a/template.html @@ -164,7 +164,7 @@ public void Parse_SpecialHtmlCharacters_PreservedInContent() var files = DiffParser.Parse(diff); var lines = files[0].Hunks[0].Lines; - // Content must contain raw <, >, ", & — no HTML encoding at parse time + // Parser must pass through <, >, ", & verbatim — DiffView's @() handles encoding Assert.Equal("
", lines[0].Content); Assert.Equal(" old & value", lines[1].Content); Assert.Equal(" new & value", lines[2].Content); diff --git a/PolyPilot/Models/DiffParser.cs b/PolyPilot/Models/DiffParser.cs index 1c37a3ab53..75f4b2224d 100644 --- a/PolyPilot/Models/DiffParser.cs +++ b/PolyPilot/Models/DiffParser.cs @@ -1,5 +1,4 @@ using System.Text; -using System.Web; namespace PolyPilot.Models;