Files
wordZero/test/template_style_test.go
zero 971f3bcca5 增加if else语法支持
完善模板渲染代码
2025-06-04 18:01:52 +08:00

413 lines
12 KiB
Go

package test
import (
"fmt"
"testing"
"time"
"github.com/ZeroHawkeye/wordZero/pkg/document"
"github.com/ZeroHawkeye/wordZero/pkg/style"
)
// TestTemplateStylePreservation 测试模板渲染时样式保持
func TestTemplateStylePreservation(t *testing.T) {
fmt.Println("=== 模板样式保持测试 ===")
// 1. 创建带有丰富样式的模板文档
templateDoc := document.New()
// 添加标题段落,使用自定义样式
titlePara := templateDoc.AddParagraph("项目报告:{{projectName}}")
titlePara.SetStyle(style.StyleHeading1)
// 添加副标题段落
subtitlePara := templateDoc.AddParagraph("报告人:{{author}}")
subtitlePara.SetStyle(style.StyleHeading2)
// 添加正文段落,包含格式化的文本
bodyPara := templateDoc.AddParagraph("")
// 创建包含不同格式的Run
normalRun := &document.Run{
Text: document.Text{Content: "项目状态:"},
Properties: &document.RunProperties{
FontFamily: &document.FontFamily{
ASCII: "Arial",
HAnsi: "Arial",
EastAsia: "微软雅黑",
},
FontSize: &document.FontSize{Val: "24"}, // 12pt
},
}
boldRun := &document.Run{
Properties: &document.RunProperties{
Bold: &document.Bold{},
FontFamily: &document.FontFamily{
ASCII: "Arial",
HAnsi: "Arial",
EastAsia: "微软雅黑",
},
FontSize: &document.FontSize{Val: "24"},
Color: &document.Color{Val: "FF0000"}, // 红色
},
Text: document.Text{Content: "{{status}}"},
}
endRun := &document.Run{
Text: document.Text{Content: ",进度:"},
Properties: &document.RunProperties{
FontFamily: &document.FontFamily{
ASCII: "Arial",
HAnsi: "Arial",
EastAsia: "微软雅黑",
},
FontSize: &document.FontSize{Val: "24"},
},
}
progressRun := &document.Run{
Properties: &document.RunProperties{
Bold: &document.Bold{},
Italic: &document.Italic{},
FontFamily: &document.FontFamily{
ASCII: "Arial",
HAnsi: "Arial",
EastAsia: "微软雅黑",
},
FontSize: &document.FontSize{Val: "28"}, // 14pt
Color: &document.Color{Val: "008000"}, // 绿色
},
Text: document.Text{Content: "{{progress}}%"},
}
bodyPara.Runs = []document.Run{*normalRun, *boldRun, *endRun, *progressRun}
// 创建带样式的表格
tableConfig := &document.TableConfig{
Rows: 2,
Cols: 3,
}
table := templateDoc.AddTable(tableConfig)
// 设置表格头部样式
headerRow := table.Rows[0]
for i, cell := range headerRow.Cells {
headers := []string{"任务", "负责人", "状态"}
para := &document.Paragraph{
Properties: &document.ParagraphProperties{
ParagraphStyle: &document.ParagraphStyle{Val: style.StyleHeading3},
},
Runs: []document.Run{{
Text: document.Text{Content: headers[i]},
Properties: &document.RunProperties{
Bold: &document.Bold{},
FontFamily: &document.FontFamily{
ASCII: "Calibri",
HAnsi: "Calibri",
EastAsia: "宋体",
},
FontSize: &document.FontSize{Val: "22"}, // 11pt
Color: &document.Color{Val: "FFFFFF"}, // 白色
},
}},
}
cell.Paragraphs = []document.Paragraph{*para}
}
// 设置数据行模板
dataRow := table.Rows[1]
templates := []string{"{{#each tasks}}", "{{name}}", "{{assignee}}", "{{status}}", "{{/each}}"}
for i, cell := range dataRow.Cells {
if i < len(templates) {
para := &document.Paragraph{
Properties: &document.ParagraphProperties{
ParagraphStyle: &document.ParagraphStyle{Val: style.StyleNormal},
},
Runs: []document.Run{{
Text: document.Text{Content: templates[i]},
Properties: &document.RunProperties{
FontFamily: &document.FontFamily{
ASCII: "Times New Roman",
HAnsi: "Times New Roman",
EastAsia: "宋体",
},
FontSize: &document.FontSize{Val: "20"}, // 10pt
Color: &document.Color{Val: "000080"}, // 深蓝色
},
}},
}
cell.Paragraphs = []document.Paragraph{*para}
}
}
// 保存模板文档
templateFile := "test/output/style_template.docx"
err := templateDoc.Save(templateFile)
if err != nil {
t.Fatalf("保存模板文档失败: %v", err)
}
fmt.Printf("✓ 创建样式模板文档: %s\n", templateFile)
// 2. 从模板文档加载模板
engine := document.NewTemplateEngine()
_, err = engine.LoadTemplateFromDocument("style_template", templateDoc)
if err != nil {
t.Fatalf("加载模板失败: %v", err)
}
// 3. 准备测试数据
data := document.NewTemplateData()
data.SetVariable("projectName", "WordZero 开发项目")
data.SetVariable("author", "张开发")
data.SetVariable("status", "进行中")
data.SetVariable("progress", "75")
// 设置表格数据
tasks := []interface{}{
map[string]interface{}{
"name": "文档解析",
"assignee": "张三",
"status": "已完成",
},
map[string]interface{}{
"name": "样式系统",
"assignee": "李四",
"status": "进行中",
},
map[string]interface{}{
"name": "测试用例",
"assignee": "王五",
"status": "待开始",
},
}
data.SetList("tasks", tasks)
// 4. 渲染模板
resultDoc, err := engine.RenderTemplateToDocument("style_template", data)
if err != nil {
t.Fatalf("渲染模板失败: %v", err)
}
// 5. 保存结果文档
outputFile := "test/output/style_result_" + time.Now().Format("20060102_150405") + ".docx"
err = resultDoc.Save(outputFile)
if err != nil {
t.Fatalf("保存结果文档失败: %v", err)
}
fmt.Printf("✓ 生成结果文档: %s\n", outputFile)
// 6. 验证样式是否保持
verifyDocumentStyles(t, resultDoc)
fmt.Println("✓ 模板样式保持测试完成")
}
// verifyDocumentStyles 验证文档样式是否正确保持
func verifyDocumentStyles(t *testing.T, doc *document.Document) {
fmt.Println("\n=== 验证样式保持情况 ===")
// 检查文档元素
if len(doc.Body.Elements) == 0 {
t.Error("文档没有元素")
return
}
elementCount := 0
styledElements := 0
for i, element := range doc.Body.Elements {
elementCount++
switch elem := element.(type) {
case *document.Paragraph:
fmt.Printf("段落 %d: ", i+1)
// 检查段落样式
if elem.Properties != nil && elem.Properties.ParagraphStyle != nil {
fmt.Printf("段落样式=%s, ", elem.Properties.ParagraphStyle.Val)
styledElements++
} else {
fmt.Printf("段落样式=无, ")
}
// 检查Run样式
runStyleCount := 0
for j, run := range elem.Runs {
if run.Properties != nil {
runStyleCount++
// 检查关键样式属性
hasFont := run.Properties.FontFamily != nil
hasBold := run.Properties.Bold != nil
hasColor := run.Properties.Color != nil
hasSize := run.Properties.FontSize != nil
fmt.Printf("Run%d(字体:%t,粗体:%t,颜色:%t,大小:%t) ",
j+1, hasFont, hasBold, hasColor, hasSize)
}
}
fmt.Printf("(共%d个带样式Run)\n", runStyleCount)
case *document.Table:
fmt.Printf("表格 %d: %d行%d列\n", i+1, len(elem.Rows), len(elem.Rows[0].Cells))
// 检查表格样式
tableStyledCells := 0
for rowIdx, row := range elem.Rows {
for cellIdx, cell := range row.Cells {
for paraIdx, para := range cell.Paragraphs {
if para.Properties != nil && para.Properties.ParagraphStyle != nil {
tableStyledCells++
fmt.Printf(" 行%d列%d段落%d: 样式=%s\n",
rowIdx+1, cellIdx+1, paraIdx+1, para.Properties.ParagraphStyle.Val)
}
for runIdx, run := range para.Runs {
if run.Properties != nil {
hasFont := run.Properties.FontFamily != nil
hasBold := run.Properties.Bold != nil
hasColor := run.Properties.Color != nil
hasSize := run.Properties.FontSize != nil
if hasFont || hasBold || hasColor || hasSize {
fmt.Printf(" Run%d: 字体:%t,粗体:%t,颜色:%t,大小:%t\n",
runIdx+1, hasFont, hasBold, hasColor, hasSize)
}
}
}
}
}
}
if tableStyledCells > 0 {
styledElements++
fmt.Printf(" 表格中有 %d 个带样式的单元格\n", tableStyledCells)
}
}
}
fmt.Printf("\n总结: 共 %d 个元素,其中 %d 个有样式信息\n", elementCount, styledElements)
// 基本验证
if elementCount == 0 {
t.Error("文档中没有元素")
}
if styledElements == 0 {
t.Error("❌ 严重问题:所有样式都丢失了!")
} else {
fmt.Printf("✓ 检测到 %d 个元素保持了样式\n", styledElements)
}
}
// TestTemplateStyleIssues 专门测试样式问题的原因
func TestTemplateStyleIssues(t *testing.T) {
fmt.Println("\n=== 样式问题诊断测试 ===")
// 创建简单的模板文档
templateDoc := document.New()
// 添加一个带样式的段落
para := templateDoc.AddParagraph("测试变量:{{testVar}}")
para.SetStyle(style.StyleHeading1)
// 检查模板文档的样式
fmt.Println("模板文档检查:")
if para.Properties != nil && para.Properties.ParagraphStyle != nil {
fmt.Printf("✓ 段落样式: %s\n", para.Properties.ParagraphStyle.Val)
} else {
fmt.Println("❌ 段落没有样式")
}
// 检查样式管理器
styleManager := templateDoc.GetStyleManager()
heading1Style := styleManager.GetStyle(style.StyleHeading1)
if heading1Style != nil {
fmt.Printf("✓ StyleManager中存在Heading1样式: %s\n", heading1Style.StyleID)
} else {
fmt.Println("❌ StyleManager中缺少Heading1样式")
}
// 加载为模板
engine := document.NewTemplateEngine()
template, err := engine.LoadTemplateFromDocument("test_template", templateDoc)
if err != nil {
t.Fatalf("加载模板失败: %v", err)
}
// 检查模板的BaseDoc
if template.BaseDoc != nil {
fmt.Println("✓ 模板有BaseDoc")
// 检查BaseDoc的样式管理器
if template.BaseDoc.GetStyleManager() != nil {
fmt.Println("✓ BaseDoc有样式管理器")
baseHeading1 := template.BaseDoc.GetStyleManager().GetStyle(style.StyleHeading1)
if baseHeading1 != nil {
fmt.Printf("✓ BaseDoc样式管理器中有Heading1: %s\n", baseHeading1.StyleID)
} else {
fmt.Println("❌ BaseDoc样式管理器中缺少Heading1")
}
} else {
fmt.Println("❌ BaseDoc没有样式管理器")
}
} else {
fmt.Println("❌ 模板没有BaseDoc")
}
// 渲染模板
data := document.NewTemplateData()
data.SetVariable("testVar", "测试值")
resultDoc, err := engine.RenderTemplateToDocument("test_template", data)
if err != nil {
t.Fatalf("渲染失败: %v", err)
}
// 检查结果文档
fmt.Println("\n结果文档检查:")
if len(resultDoc.Body.Elements) > 0 {
if para, ok := resultDoc.Body.Elements[0].(*document.Paragraph); ok {
if para.Properties != nil && para.Properties.ParagraphStyle != nil {
fmt.Printf("✓ 结果段落样式: %s\n", para.Properties.ParagraphStyle.Val)
} else {
fmt.Println("❌ 结果段落没有样式")
}
// 检查文本内容
fullText := ""
for _, run := range para.Runs {
fullText += run.Text.Content
}
fmt.Printf("文本内容: %s\n", fullText)
}
}
// 检查结果文档的样式管理器
resultStyleManager := resultDoc.GetStyleManager()
if resultStyleManager != nil {
fmt.Println("✓ 结果文档有样式管理器")
resultHeading1 := resultStyleManager.GetStyle(style.StyleHeading1)
if resultHeading1 != nil {
fmt.Printf("✓ 结果样式管理器中有Heading1: %s\n", resultHeading1.StyleID)
} else {
fmt.Println("❌ 结果样式管理器中缺少Heading1")
}
} else {
fmt.Println("❌ 结果文档没有样式管理器")
}
// 保存结果用于手动检查
outputFile := "test/output/style_diagnosis_" + time.Now().Format("20060102_150405") + ".docx"
err = resultDoc.Save(outputFile)
if err != nil {
t.Fatalf("保存失败: %v", err)
}
fmt.Printf("✓ 诊断结果保存到: %s\n", outputFile)
}