Files
RenewCMS/test/body_converter_documents_test.go
T

79 lines
3.0 KiB
Go

package test
import (
domainArticle "RenewCMS/internal/domain/article"
"RenewCMS/internal/infrastructure/markdown"
"encoding/json"
"reflect"
"strings"
"testing"
)
const hostileBody = `<h1>Title</h1><p>Intro <strong>bold</strong><script>alert(1)</script></p><style>p{}</style><iframe src="x"></iframe><ul><li><p>one</p><ul><li><p>deep</p></li></ul></li></ul><div><span style="color:red">kept</span></div><img src="/i.png" alt="I"><pre><code>a<script>z</script></code></pre>`
func TestConverterNeverLeaksRawHtml(t *testing.T) {
converter := markdown.NewConverter()
for _, format := range []domainArticle.BodyFormat{domainArticle.BodyFormatMarkdown, domainArticle.BodyFormatJSON} {
got, err := converter.Render(hostileBody, format)
if err != nil {
t.Fatalf("%s: unexpected error: %v", format, err)
}
for _, forbidden := range []string{"<script", "<style", "<iframe", "<span", "alert(1)", "p{}"} {
if strings.Contains(got, forbidden) {
t.Errorf("%s output leaks %q: %s", format, forbidden, got)
}
}
}
}
func TestJsonConverterCombinedDocument(t *testing.T) {
converter := markdown.NewConverter()
got, err := converter.Render(hostileBody, domainArticle.BodyFormatJSON)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var blocks []map[string]any
if err := json.Unmarshal([]byte(got), &blocks); err != nil {
t.Fatalf("body is not a JSON array: %v", err)
}
var types []string
for _, b := range blocks {
types = append(types, b["type"].(string))
}
expected := []string{"heading", "paragraph", "list", "paragraph", "image", "code"}
if !reflect.DeepEqual(types, expected) {
t.Errorf("expected block types %v, got %v", expected, types)
}
}
func TestJsonConverterEmptyBodyIsArray(t *testing.T) {
converter := markdown.NewConverter()
for _, source := range []string{"", " ", "<script>x</script>"} {
got, err := converter.Render(source, domainArticle.BodyFormatJSON)
if err != nil || got != "[]" {
t.Errorf("%q: expected [] got %q, %v", source, got, err)
}
}
}
func TestMarkdownConverterCodeBlockText(t *testing.T) {
converter := markdown.NewConverter()
examples := []struct{ name, html, markdown string }{
{"text node kept", "<pre><code>x</code></pre>", "```\nx\n```"},
{"skipped element dropped", "<pre><code>a<script>z</script>b</code></pre>", "```\nab\n```"},
{"style dropped", "<pre><code>a<style>z</style></code></pre>", "```\na\n```"},
{"break becomes newline", "<pre><code>a<br>b</code></pre>", "```\na\nb\n```"},
{"nested element text kept", "<pre><code>a<span>b</span>c</code></pre>", "```\nabc\n```"},
{"trailing newline trimmed", "<pre><code>a\n</code></pre>", "```\na\n```"},
{"fence grows around backticks", "<pre><code>```\nx</code></pre>", "````\n```\nx\n````"},
}
for _, example := range examples {
t.Run(example.name, func(t *testing.T) {
got, err := converter.Render(example.html, domainArticle.BodyFormatMarkdown)
if err != nil || got != example.markdown {
t.Errorf("expected %q, got %q, %v", example.markdown, got, err)
}
})
}
}