| 🛟 Updated. 28d5985 k33g 18h ago | 1 | package syntax |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | // wantHTML is wantLine for HTML. |
| 6 | func wantHTML(t *testing.T, src string, line int, want ...string) { |
| 7 | t.Helper() |
| 8 | wantLine(t, LanguageHTML, src, line, want...) |
| 9 | } |
| 10 | |
| 11 | func TestHTMLColoursATag(t *testing.T) { |
| 12 | wantHTML(t, "<p>", 0, "<p:tag", ">:tag") |
| 13 | wantHTML(t, "</p>", 0, "</p:tag", ">:tag") |
| 14 | wantHTML(t, "<br/>", 0, "<br:tag", "/>:tag") |
| 15 | } |
| 16 | |
| 17 | func TestHTMLColoursAttributesAndTheirValues(t *testing.T) { |
| 18 | wantHTML(t, `<div class="box">`, 0, |
| 19 | "<div:tag", "class:attribute", "=:operator", `"box":string`, ">:tag") |
| 20 | } |
| 21 | |
| 22 | func TestHTMLColoursTheAttributeSpellingsInTheWild(t *testing.T) { |
| 23 | wantHTML(t, `<a data-id="1" xlink:href="#" @click="go">`, 0, |
| 24 | "<a:tag", |
| 25 | "data-id:attribute", "=:operator", `"1":string`, |
| 26 | "xlink:href:attribute", "=:operator", `"#":string`, |
| 27 | "@click:attribute", "=:operator", `"go":string`, |
| 28 | ">:tag") |
| 29 | } |
| 30 | |
| 31 | func TestTextBetweenTagsIsNotColoured(t *testing.T) { |
| 32 | got := spansOf(t, LanguageHTML, "<p>hello</p>", 0) |
| 33 | want := []string{"<p:tag", ">:tag", "</p:tag", ">:tag"} |
| 34 | if len(got) != len(want) { |
| 35 | t.Fatalf("got %v, want %v", got, want) |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | func TestHTMLColoursAComment(t *testing.T) { |
| 40 | wantHTML(t, "<!-- a note -->", 0, "<!-- a note -->:comment") |
| 41 | wantHTML(t, "<p><!-- x --></p>", 0, "<p:tag", ">:tag", "<!-- x -->:comment", "</p:tag", ">:tag") |
| 42 | } |
| 43 | |
| 44 | func TestAnHTMLCommentCarriesAcrossLines(t *testing.T) { |
| 45 | src := "<!-- first\n second\n third --><p>" |
| 46 | |
| 47 | wantHTML(t, src, 0, "<!-- first:comment") |
| 48 | wantHTML(t, src, 1, " second:comment") |
| 49 | wantHTML(t, src, 2, " third -->:comment", "<p:tag", ">:tag") |
| 50 | } |
| 51 | |
| 52 | func TestTagsInsideACommentAreNotColoured(t *testing.T) { |
| 53 | src := "<!--\n<div class=\"x\">\n-->" |
| 54 | |
| 55 | wantHTML(t, src, 1, `<div class="x">:comment`) |
| 56 | } |
| 57 | |
| 58 | func TestHTMLColoursTheDoctype(t *testing.T) { |
| 59 | wantHTML(t, "<!DOCTYPE html>", 0, "<!DOCTYPE html>:keyword") |
| 60 | } |
| 61 | |
| 62 | func TestHTMLColoursEntities(t *testing.T) { |
| 63 | wantHTML(t, "a & b", 0, "&:constant") |
| 64 | wantHTML(t, "© 2026", 0, "©:constant") |
| 65 | } |
| 66 | |
| 67 | func TestABareAmpersandIsLeftAlone(t *testing.T) { |
| 68 | // It is legal text, and colouring the rest of a paragraph after one would |
| 69 | // be worse than colouring nothing. |
| 70 | if got := spansOf(t, LanguageHTML, "Marks & Spencer", 0); len(got) != 0 { |
| 71 | t.Errorf("a bare ampersand gave %v, want nothing coloured", got) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | func TestScriptContentsAreNotColouredAsJavaScript(t *testing.T) { |
| 76 | // Documented as out of scope: it needs the element followed across lines |
| 77 | // and another scanner's columns mapped back out. |
| 78 | src := "<script>\nconst x = 1\n</script>" |
| 79 | |
| 80 | if got := spansOf(t, LanguageHTML, src, 1); len(got) != 0 { |
| 81 | t.Errorf("the body of a script gave %v, want plain text", got) |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | func TestAnUnclosedTagIsColouredToWhatIsThere(t *testing.T) { |
| 86 | // A tag is unfinished most of the time it is being typed. |
| 87 | wantHTML(t, `<div class="bo`, 0, "<div:tag", "class:attribute", "=:operator", `"bo:string`) |
| 88 | } |
| 89 | |
| 90 | func TestHTMLGivesOneEntryPerLine(t *testing.T) { |
| 91 | if got := len(Highlight(LanguageHTML, "a\nb\n\nc\n")); got != 5 { |
| 92 | t.Errorf("Highlight() returned %d lines for a 5-line document", got) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | func TestHTMLSpansStayInsideTheirLine(t *testing.T) { |
| 97 | src := "<!DOCTYPE html>\n<html lang=\"en\">\n<!-- c\nd -->\n<p>& text</p>\n" |
| 98 | assertSpansFit(t, LanguageHTML, src) |
| 99 | } |
| 100 | |
| 101 | func TestHTMLColoursAPageWithAccents(t *testing.T) { |
| 102 | // A byte offset would put this line's spans out of step with what is drawn. |
| 103 | wantHTML(t, `<p title="éléphant">évidemment</p>`, 0, |
| 104 | "<p:tag", "title:attribute", "=:operator", `"éléphant":string`, ">:tag", "</p:tag", ">:tag") |
| 105 | } |