Use Unicode placeholders to replace HTML tags and HTML entities first, then do diff, then recover the HTML tags and HTML entities. Now the code diff with highlight has stable behavior, and won't emit broken tags.
Showing the changes to services/gitdiff/gitdiff_test.go (1 of 5 files). Show all
Unified · Split
| @@ -7,7 +7,6 @@ package gitdiff · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | import ( | 8 | import ( |
| 9 | "fmt" | 9 | "fmt" |
| 10 | "html/template" | ||
| 11 | "strconv" | 10 | "strconv" |
| 12 | "strings" | 11 | "strings" |
| 13 | "testing" | 12 | "testing" |
| @@ -17,93 +16,27 @@ import ( · 3 unmodified lines | |||
| 17 | "code.gitea.io/gitea/models/unittest" | 16 | "code.gitea.io/gitea/models/unittest" |
| 18 | user_model "code.gitea.io/gitea/models/user" | 17 | user_model "code.gitea.io/gitea/models/user" |
| 19 | "code.gitea.io/gitea/modules/git" | 18 | "code.gitea.io/gitea/modules/git" |
| 20 | "code.gitea.io/gitea/modules/highlight" | ||
| 21 | "code.gitea.io/gitea/modules/json" | 19 | "code.gitea.io/gitea/modules/json" |
| 22 | "code.gitea.io/gitea/modules/setting" | 20 | "code.gitea.io/gitea/modules/setting" |
| 23 | 21 | ||
| 24 | dmp "github.com/sergi/go-diff/diffmatchpatch" | 22 | dmp "github.com/sergi/go-diff/diffmatchpatch" |
| 25 | "github.com/stretchr/testify/assert" | 23 | "github.com/stretchr/testify/assert" |
| 26 | "gopkg.in/ini.v1" | ||
| 27 | ) | 24 | ) |
| 28 | 25 | ||
| 29 | func assertEqual(t *testing.T, s1 string, s2 template.HTML) { | ||
| 30 | if s1 != string(s2) { | ||
| 31 | t.Errorf("Did not receive expected results:\nExpected: %s\nActual: %s", s1, s2) | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | func TestDiffToHTML(t *testing.T) { | 26 | func TestDiffToHTML(t *testing.T) { |
| 36 | setting.Cfg = ini.Empty() | 27 | assert.Equal(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{ |
| 37 | assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML("", []dmp.Diff{ | ||
| 38 | {Type: dmp.DiffEqual, Text: "foo "}, | 28 | {Type: dmp.DiffEqual, Text: "foo "}, |
| 39 | {Type: dmp.DiffInsert, Text: "bar"}, | 29 | {Type: dmp.DiffInsert, Text: "bar"}, |
| 40 | {Type: dmp.DiffDelete, Text: " baz"}, | 30 | {Type: dmp.DiffDelete, Text: " baz"}, |
| 41 | {Type: dmp.DiffEqual, Text: " biz"}, | 31 | {Type: dmp.DiffEqual, Text: " biz"}, |
| 42 | }, DiffLineAdd).Content) | 32 | }, DiffLineAdd)) |
| 43 | 33 | ||
| 44 | assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML("", []dmp.Diff{ | 34 | assert.Equal(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{ |
| 45 | {Type: dmp.DiffEqual, Text: "foo "}, | 35 | {Type: dmp.DiffEqual, Text: "foo "}, |
| 46 | {Type: dmp.DiffDelete, Text: "bar"}, | 36 | {Type: dmp.DiffDelete, Text: "bar"}, |
| 47 | {Type: dmp.DiffInsert, Text: " baz"}, | 37 | {Type: dmp.DiffInsert, Text: " baz"}, |
| 48 | {Type: dmp.DiffEqual, Text: " biz"}, | 38 | {Type: dmp.DiffEqual, Text: " biz"}, |
| 49 | }, DiffLineDel).Content) | 39 | }, DiffLineDel)) |
| 50 | |||
| 51 | assertEqual(t, "<span class=\"k\">if</span> <span class=\"p\">!</span><span class=\"nx\">nohl</span> <span class=\"o\">&&</span> <span class=\"added-code\"><span class=\"p\">(</span></span><span class=\"nx\">lexer</span> <span class=\"o\">!=</span> <span class=\"kc\">nil</span><span class=\"added-code\"> <span class=\"o\">||</span> <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">GuessLanguage</span><span class=\"p\">)</span></span> <span class=\"p\">{</span>", diffToHTML("", []dmp.Diff{ | ||
| 52 | {Type: dmp.DiffEqual, Text: "<span class=\"k\">if</span> <span class=\"p\">!</span><span class=\"nx\">nohl</span> <span class=\"o\">&&</span> <span class=\""}, | ||
| 53 | {Type: dmp.DiffInsert, Text: "p\">(</span><span class=\""}, | ||
| 54 | {Type: dmp.DiffEqual, Text: "nx\">lexer</span> <span class=\"o\">!=</span> <span class=\"kc\">nil"}, | ||
| 55 | {Type: dmp.DiffInsert, Text: "</span> <span class=\"o\">||</span> <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">GuessLanguage</span><span class=\"p\">)"}, | ||
| 56 | {Type: dmp.DiffEqual, Text: "</span> <span class=\"p\">{</span>"}, | ||
| 57 | }, DiffLineAdd).Content) | ||
| 58 | |||
| 59 | assertEqual(t, "<span class=\"nx\">tagURL</span> <span class=\"o\">:=</span> <span class=\"removed-code\"><span class=\"nx\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Sprintf</span><span class=\"p\">(</span><span class=\"s\">"## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s"</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone\"</span></span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">BaseURL</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Owner</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Repo</span><span class=\"p\">,</span> <span class=\"removed-code\"><span class=\"nx\">from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID</span><span class=\"p\">,</span> <span class=\"nx\">time</span><span class=\"p\">.</span><span class=\"nf\">Now</span><span class=\"p\">(</span><span class=\"p\">)</span><span class=\"p\">.</span><span class=\"nf\">Format</span><span class=\"p\">(</span><span class=\"s\">"2006-01-02"</span><span class=\"p\">)</span></span><span class=\"p\">)</span>", diffToHTML("", []dmp.Diff{ | ||
| 60 | {Type: dmp.DiffEqual, Text: "<span class=\"nx\">tagURL</span> <span class=\"o\">:=</span> <span class=\"n"}, | ||
| 61 | {Type: dmp.DiffDelete, Text: "x\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Sprintf</span><span class=\"p\">(</span><span class=\"s\">"## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s"</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone\""}, | ||
| 62 | {Type: dmp.DiffInsert, Text: "f\">getGiteaTagURL</span><span class=\"p\">(</span><span class=\"nx\">client"}, | ||
| 63 | {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">BaseURL</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Owner</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Repo</span><span class=\"p\">,</span> <span class=\"nx\">"}, | ||
| 64 | {Type: dmp.DiffDelete, Text: "from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID</span><span class=\"p\">,</span> <span class=\"nx\">time</span><span class=\"p\">.</span><span class=\"nf\">Now</span><span class=\"p\">(</span><span class=\"p\">)</span><span class=\"p\">.</span><span class=\"nf\">Format</span><span class=\"p\">(</span><span class=\"s\">"2006-01-02"</span><span class=\"p\">)"}, | ||
| 65 | {Type: dmp.DiffInsert, Text: "ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone</span><span class=\"p\">,</span> <span class=\"nx\">from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID"}, | ||
| 66 | {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">)</span>"}, | ||
| 67 | }, DiffLineDel).Content) | ||
| 68 | |||
| 69 | assertEqual(t, "<span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nf\">WrapperRenderer</span><span class=\"p\">(</span><span class=\"nx\">w</span><span class=\"p\">,</span> <span class=\"removed-code\"><span class=\"nx\">language</span><span class=\"p\">,</span> <span class=\"kc\">true</span><span class=\"p\">,</span> <span class=\"nx\">attrs</span></span><span class=\"p\">,</span> <span class=\"kc\">false</span><span class=\"p\">)</span>", diffToHTML("", []dmp.Diff{ | ||
| 70 | {Type: dmp.DiffEqual, Text: "<span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nf\">WrapperRenderer</span><span class=\"p\">(</span><span class=\"nx\">w</span><span class=\"p\">,</span> <span class=\"nx\">"}, | ||
| 71 | {Type: dmp.DiffDelete, Text: "language</span><span "}, | ||
| 72 | {Type: dmp.DiffEqual, Text: "c"}, | ||
| 73 | {Type: dmp.DiffDelete, Text: "lass=\"p\">,</span> <span class=\"kc\">true</span><span class=\"p\">,</span> <span class=\"nx\">attrs"}, | ||
| 74 | {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">,</span> <span class=\"kc\">false</span><span class=\"p\">)</span>"}, | ||
| 75 | }, DiffLineDel).Content) | ||
| 76 | |||
| 77 | assertEqual(t, "<span class=\"added-code\">language</span><span class=\"p\">,</span> <span class=\"kc\">true</span><span class=\"p\">,</span> <span class=\"nx\">attrs</span></span><span class=\"p\">,</span> <span class=\"kc\">false</span><span class=\"p\">)</span>", diffToHTML("", []dmp.Diff{ | ||
| 78 | {Type: dmp.DiffInsert, Text: "language</span><span "}, | ||
| 79 | {Type: dmp.DiffEqual, Text: "c"}, | ||
| 80 | {Type: dmp.DiffInsert, Text: "lass=\"p\">,</span> <span class=\"kc\">true</span><span class=\"p\">,</span> <span class=\"nx\">attrs"}, | ||
| 81 | {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">,</span> <span class=\"kc\">false</span><span class=\"p\">)</span>"}, | ||
| 82 | }, DiffLineAdd).Content) | ||
| 83 | |||
| 84 | assertEqual(t, "<span class=\"k\">print</span><span class=\"added-code\"><span class=\"p\">(</span></span><span class=\"sa\"></span><span class=\"s2\">"</span><span class=\"s2\">// </span><span class=\"s2\">"</span><span class=\"p\">,</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"added-code\"><span class=\"p\">)</span></span>", diffToHTML("", []dmp.Diff{ | ||
| 85 | {Type: dmp.DiffEqual, Text: "<span class=\"k\">print</span>"}, | ||
| 86 | {Type: dmp.DiffInsert, Text: "<span"}, | ||
| 87 | {Type: dmp.DiffEqual, Text: " "}, | ||
| 88 | {Type: dmp.DiffInsert, Text: "class=\"p\">(</span>"}, | ||
| 89 | {Type: dmp.DiffEqual, Text: "<span class=\"sa\"></span><span class=\"s2\">"</span><span class=\"s2\">// </span><span class=\"s2\">"</span><span class=\"p\">,</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span>"}, | ||
| 90 | {Type: dmp.DiffInsert, Text: "<span class=\"p\">)</span>"}, | ||
| 91 | }, DiffLineAdd).Content) | ||
| 92 | |||
| 93 | assertEqual(t, "sh <span class=\"added-code\">'useradd -u $(stat -c "%u" .gitignore) jenkins'</span>", diffToHTML("", []dmp.Diff{ | ||
| 94 | {Type: dmp.DiffEqual, Text: "sh "}, | ||
| 95 | {Type: dmp.DiffDelete, Text: "4;useradd -u 111 jenkins""}, | ||
| 96 | {Type: dmp.DiffInsert, Text: "9;useradd -u $(stat -c "%u" .gitignore) jenkins'"}, | ||
| 97 | {Type: dmp.DiffEqual, Text: ";"}, | ||
| 98 | }, DiffLineAdd).Content) | ||
| 99 | |||
| 100 | assertEqual(t, "<span class=\"x\"> <h<span class=\"added-code\">4 class="release-list-title df ac"</span>></span>", diffToHTML("", []dmp.Diff{ | ||
| 101 | {Type: dmp.DiffEqual, Text: "<span class=\"x\"> <h"}, | ||
| 102 | {Type: dmp.DiffInsert, Text: "4 class=&#"}, | ||
| 103 | {Type: dmp.DiffEqual, Text: "3"}, | ||
| 104 | {Type: dmp.DiffInsert, Text: "4;release-list-title df ac""}, | ||
| 105 | {Type: dmp.DiffEqual, Text: "></span>"}, | ||
| 106 | }, DiffLineAdd).Content) | ||
| 107 | } | 40 | } |
| 108 | 41 | ||
| 109 | func TestParsePatch_skipTo(t *testing.T) { | 42 | func TestParsePatch_skipTo(t *testing.T) { |
| @@ -592,7 +525,6 @@ index 0000000..6bb8f39 · 482 unmodified lines | |||
| 592 | if err != nil { | 525 | if err != nil { |
| 593 | t.Errorf("ParsePatch failed: %s", err) | 526 | t.Errorf("ParsePatch failed: %s", err) |
| 594 | } | 527 | } |
| 595 | println(result) | ||
| 596 | 528 | ||
| 597 | diff2 := `diff --git "a/A \\ B" "b/A \\ B" | 529 | diff2 := `diff --git "a/A \\ B" "b/A \\ B" |
| 598 | --- "a/A \\ B" | 530 | --- "a/A \\ B" |
| @@ -712,18 +644,6 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { · 113 unmodified lines | |||
| 712 | } | 644 | } |
| 713 | } | 645 | } |
| 714 | 646 | ||
| 715 | func TestDiffToHTML_14231(t *testing.T) { | ||
| 716 | setting.Cfg = ini.Empty() | ||
| 717 | diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", "", " run()\n"), highlight.Code("main.v", "", " run(db)\n"), true) | ||
| 718 | diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) | ||
| 719 | |||
| 720 | expected := `<span class="line"><span class="cl"> <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span></span><span class="o">)</span> | ||
| 721 | </span></span>` | ||
| 722 | output := diffToHTML("main.v", diffRecord, DiffLineAdd) | ||
| 723 | |||
| 724 | assertEqual(t, expected, output.Content) | ||
| 725 | } | ||
| 726 | |||
| 727 | func TestNoCrashes(t *testing.T) { | 647 | func TestNoCrashes(t *testing.T) { |
| 728 | type testcase struct { | 648 | type testcase struct { |
| 729 | gitdiff string | 649 | gitdiff string |