96 lines
3.7 KiB
Go
96 lines
3.7 KiB
Go
package service
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseDramaSourceRejectsDisguisedAndExecutableContent(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
filename string
|
|
data []byte
|
|
raw string
|
|
}{
|
|
{name: "pdf renamed txt", filename: "novel.txt", data: []byte("%PDF-1.7\ncontent")},
|
|
{name: "zip renamed txt", filename: "novel.txt", data: []byte{'P', 'K', 3, 4, 1, 2, 3}},
|
|
{name: "html after long prefix", filename: "novel.txt", data: []byte(strings.Repeat("正文", 3000) + "<script>alert(1)</script>")},
|
|
{name: "script pasted", raw: "小说正文\njavascript:alert(1)"},
|
|
{name: "binary pasted", raw: "正文\x00内容"},
|
|
}
|
|
for _, test := range cases {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if _, _, err := parseDramaSource(test.filename, test.data, test.raw); err == nil {
|
|
t.Fatal("expected unsafe import to be rejected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractDOCXReadsParagraphsAndValidatesWordPackage(t *testing.T) {
|
|
valid := makeTestDOCX(t, `<?xml version="1.0"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/></Types>`, nil)
|
|
text, err := extractDOCX(valid)
|
|
if err != nil {
|
|
t.Fatalf("extractDOCX returned error: %v", err)
|
|
}
|
|
if !strings.Contains(text, "第一章 开始") || !strings.Contains(text, "这是正文") {
|
|
t.Fatalf("unexpected extracted text: %q", text)
|
|
}
|
|
|
|
fake := makeTestDOCX(t, `<?xml version="1.0"?><Types/>`, nil)
|
|
if _, err := extractDOCX(fake); err == nil {
|
|
t.Fatal("expected ZIP with fake DOCX structure to be rejected")
|
|
}
|
|
|
|
macro := makeTestDOCX(t, `<?xml version="1.0"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/></Types>`, map[string]string{"word/vbaProject.bin": "macro"})
|
|
if _, err := extractDOCX(macro); err == nil {
|
|
t.Fatal("expected macro-enabled package to be rejected")
|
|
}
|
|
}
|
|
|
|
func TestSplitDramaChaptersPreservesOriginalText(t *testing.T) {
|
|
source := "作品说明\n\n第一章 初见\n正文一\n\n第二章 重逢\n正文二"
|
|
chapters := splitDramaChapters(source)
|
|
if len(chapters) != 2 {
|
|
t.Fatalf("expected 2 chapters, got %d", len(chapters))
|
|
}
|
|
joined := strings.TrimSpace(chapters[0].Content + "\n\n" + chapters[1].Content)
|
|
if joined != source {
|
|
t.Fatalf("chapter splitting lost or duplicated text:\nwant: %q\n got: %q", source, joined)
|
|
}
|
|
if chapters[0].Title != "第一章 初见" || chapters[1].Title != "第二章 重逢" {
|
|
t.Fatalf("unexpected chapter titles: %#v", chapters)
|
|
}
|
|
if chapters := splitDramaChapters("没有章节标题的完整正文"); chapters != nil {
|
|
t.Fatalf("text without chapter titles must require single-episode confirmation: %#v", chapters)
|
|
}
|
|
}
|
|
|
|
func makeTestDOCX(t *testing.T, contentTypes string, extras map[string]string) []byte {
|
|
t.Helper()
|
|
var buffer bytes.Buffer
|
|
writer := zip.NewWriter(&buffer)
|
|
files := map[string]string{
|
|
"[Content_Types].xml": contentTypes,
|
|
"word/document.xml": `<?xml version="1.0"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:r><w:t>第一章 开始</w:t></w:r></w:p><w:p><w:r><w:t>这是正文</w:t></w:r></w:p></w:body></w:document>`,
|
|
}
|
|
for name, content := range extras {
|
|
files[name] = content
|
|
}
|
|
for name, content := range files {
|
|
entry, err := writer.Create(name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = entry.Write([]byte(content)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := writer.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return buffer.Bytes()
|
|
}
|