MVP: 按 07 风格重写前端 + Go 后端落地(长文/短文、编辑器、后台管理)

This commit is contained in:
Sakurasan
2026-09-20 20:56:03 +08:00
parent edee708802
commit 4d8f2de3a4
96 changed files with 6005 additions and 2602 deletions
+49
View File
@@ -0,0 +1,49 @@
package render
import (
"strings"
"testing"
)
func TestMarkdownRendersStructure(t *testing.T) {
out := Markdown("## 标题\n\n正文 **粗体**。\n\n- 一\n- 二\n\n> 引用\n")
for _, want := range []string{"<h2", "<strong>粗体</strong>", "<li>一</li>", "<blockquote>"} {
if !strings.Contains(out, want) {
t.Errorf("missing %q in %q", want, out)
}
}
}
func TestMarkdownEscapesRawHTML(t *testing.T) {
out := Markdown("<script>alert(1)</script>")
if strings.Contains(out, "<script>") {
t.Errorf("raw HTML should be escaped, got %q", out)
}
}
func TestMarkdownBlocksUnsafeSchemes(t *testing.T) {
out := Markdown(`[x](javascript:alert(1))`)
if strings.Contains(out, "javascript:") {
t.Errorf("unsafe scheme should be stripped, got %q", out)
}
}
func TestReadingMinutes(t *testing.T) {
if got := ReadingMinutes(""); got != 1 {
t.Errorf("empty content should be 1 minute, got %d", got)
}
long := strings.Repeat("字", 1200)
if got := ReadingMinutes(long); got != 3 {
t.Errorf("1200 CJK chars should be 3 minutes, got %d", got)
}
}
func TestExcerpt(t *testing.T) {
got := Excerpt("# 标题\n\n这是正文。\n\n```go\nfmt.Println()\n```", 140)
if strings.Contains(got, "fmt.Println") {
t.Errorf("code fences should be dropped, got %q", got)
}
if !strings.Contains(got, "这是正文。") {
t.Errorf("excerpt should keep body text, got %q", got)
}
}