79 lines
3.0 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|