ConvertContentH1 rewrites content only when it is HTML; a markdown source, its code samples included, is kept byte for byte and only its rendered content_html is converted, on API saves, imports, journal:fix-headings and translations. ConvertH1 and SetImageAlt keep the bytes of an unfinished tag at the end of the input.
106 lines
4.4 KiB
Go
106 lines
4.4 KiB
Go
package classes
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestConvertH1 pins ConvertH1's byte rule: only h1 tag names change.
|
|
func TestConvertH1(t *testing.T) {
|
|
cases := []struct {
|
|
in, want string
|
|
n int
|
|
}{
|
|
{"<h1>A</h1><p>x</p>", "<h2>A</h2><p>x</p>", 1},
|
|
{`<h1 class="x" id='y'>T</h1>`, `<h2 class="x" id='y'>T</h2>`, 1},
|
|
{"<H1>Up</H1>", "<h2>Up</h2>", 1},
|
|
{"<h1>a</h1>\n<h1>b</h1>", "<h2>a</h2>\n<h2>b</h2>", 2},
|
|
{"<p>no heading & text</p>", "<p>no heading & text</p>", 0},
|
|
{"<!-- <h1>c</h1> --><p>x</p>", "<!-- <h1>c</h1> --><p>x</p>", 0},
|
|
{"<script>var s = '<h1>';</script>", "<script>var s = '<h1>';</script>", 0},
|
|
{"<h10>x</h10><h1>y</h1>", "<h10>x</h10><h2>y</h2>", 1},
|
|
{"# Markdown <h1>raw</h1> a < b", "# Markdown <h2>raw</h2> a < b", 1},
|
|
{"<p>unterminated <h1>x", "<p>unterminated <h2>x", 1},
|
|
{"text <", "text <", 0},
|
|
{"", "", 0},
|
|
}
|
|
for _, c := range cases {
|
|
got, n := ConvertH1(c.in)
|
|
if got != c.want || n != c.n {
|
|
t.Errorf("ConvertH1(%q) = %q, %d; want %q, %d", c.in, got, n, c.want, c.n)
|
|
}
|
|
}
|
|
// L1 WR-03: input without a match comes back identical, and an h1
|
|
// followed by an unfinished tag keeps the tail.
|
|
for _, in := range []string{"p a <b", "x<y", "<p>a <b class=\"c", "a < b"} {
|
|
if out, n := ConvertH1(in); out != in || n != 0 {
|
|
t.Errorf("ConvertH1(%q) = %q %d", in, out, n)
|
|
}
|
|
}
|
|
if out, n := ConvertH1("<h1>x</h1><p>a <b"); out != "<h2>x</h2><p>a <b" || n != 1 {
|
|
t.Errorf("unfinished tail = %q %d", out, n)
|
|
}
|
|
}
|
|
|
|
// TestConvertContentH1 pins the body pair: content_html's count when its
|
|
// HTML had H1s, content's otherwise (a markdown body's H1 is only in its
|
|
// rendered HTML), both converted.
|
|
func TestConvertContentH1(t *testing.T) {
|
|
c, h, n := ConvertContentH1("# Title\n\ntext", "<h1>Title</h1><p>text</p>")
|
|
if c != "# Title\n\ntext" || h != "<h2>Title</h2><p>text</p>" || n != 1 {
|
|
t.Fatalf("markdown body = %q %q %d", c, h, n)
|
|
}
|
|
c, h, n = ConvertContentH1("<h1>a</h1><h1>b</h1>", "")
|
|
if c != "<h2>a</h2><h2>b</h2>" || h != "" || n != 2 {
|
|
t.Fatalf("HTML body without rendered HTML = %q %q %d", c, h, n)
|
|
}
|
|
if _, _, n := ConvertContentH1("<p>x</p>", "<p>x</p>"); n != 0 {
|
|
t.Fatal("no H1, nothing converted")
|
|
}
|
|
if CountH1(`<h1>a</h1><div><h1 class="x">b</h1></div><h2>c</h2>`) != 2 || CountH1("") != 0 {
|
|
t.Fatal("CountH1 is wrong")
|
|
}
|
|
// L1 CR-02: markdown with a fenced html sample and an inline code h1 is
|
|
// kept byte for byte; its rendered HTML has the real heading converted
|
|
// and the code still escaped.
|
|
md := "# Title\n\nExample:\n\n```html\n<h1>Hello</h1>\n```\n\nInline `<h1>` tag."
|
|
rendered, err := FormatHTML(md)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c, h, n = ConvertContentH1(md, rendered)
|
|
if c != md {
|
|
t.Fatalf("the markdown source was rewritten:\n%s", c)
|
|
}
|
|
if n != 1 || !strings.Contains(h, "<h2") || strings.Contains(h, "<h1") || !strings.Contains(h, "<h1>Hello</h1>") || !strings.Contains(h, "<code><h1></code>") {
|
|
t.Fatalf("rendered HTML = %q n=%d", h, n)
|
|
}
|
|
// Markdown without rendered HTML: nothing changes, nothing counted.
|
|
if c, h, n := ConvertContentH1("plain <h1>x</h1> text", ""); c != "plain <h1>x</h1> text" || h != "" || n != 0 {
|
|
t.Fatalf("markdown without HTML = %q %q %d", c, h, n)
|
|
}
|
|
}
|
|
|
|
// TestConvertTranslationH1 pins a locale's translated attributes,
|
|
// changed in place: content and content_html converted, other attributes
|
|
// and values that are not strings left alone (a category's pillar text
|
|
// takes the same path as a post body).
|
|
func TestConvertTranslationH1(t *testing.T) {
|
|
attrs := map[string]any{"title": "<h1>not content</h1>", "content": "<h1>Pillar</h1><p>x</p>", "content_html": 5}
|
|
if n := ConvertTranslationH1(attrs); n != 1 || attrs["content"] != "<h2>Pillar</h2><p>x</p>" || attrs["title"] != "<h1>not content</h1>" || attrs["content_html"] != 5 {
|
|
t.Fatalf("attrs = %v n=%d", attrs, n)
|
|
}
|
|
both := map[string]any{"content": "# T", "content_html": "<h1>T</h1>"}
|
|
if n := ConvertTranslationH1(both); n != 1 || both["content_html"] != "<h2>T</h2>" || both["content"] != "# T" {
|
|
t.Fatalf("both = %v n=%d", both, n)
|
|
}
|
|
if ConvertTranslationH1(nil) != 0 || ConvertTranslationH1(map[string]any{"title": "x"}) != 0 {
|
|
t.Fatal("nothing to convert")
|
|
}
|
|
md := "Sample:\n\n```html\n<h1>Hi</h1>\n```\n"
|
|
tr := map[string]any{"content": md, "content_html": "<pre><code><h1>Hi</h1></code></pre>"}
|
|
if n := ConvertTranslationH1(tr); n != 0 || tr["content"] != md {
|
|
t.Fatalf("a markdown translation was rewritten: %v n=%d", tr, n)
|
|
}
|
|
}
|