xyc
2 天以前 21a5bf7abb0b0902042e3aa567c04fa21e63801b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.trafficaudit.holiday.service;
 
import org.junit.jupiter.api.Test;
 
import java.io.ByteArrayInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
 
class HolidayTrendWordServiceTest {
 
    @Test
    void rebuildsTemplateWithSectionsChartsAndAppendix() throws Exception {
        Path template = resolveTemplate();
        byte[] templateBytes = Files.readAllBytes(template);
        HolidayTrendWordService service = new HolidayTrendWordService();
 
        List<HolidayTrendWordService.DocumentBlock> blocks = new ArrayList<>();
        blocks.add(new HolidayTrendWordService.SectionBlock("一、总体情况"));
        blocks.add(new HolidayTrendWordService.ChartBlock("客流总量", png(1),
                new HolidayTrendWordService.ImageSize(5000000L, 3000000L)));
        blocks.add(new HolidayTrendWordService.ChartBlock("客流占比", png(2), true,
                new HolidayTrendWordService.ImageSize(4000000L, 2500000L)));
        blocks.add(new HolidayTrendWordService.PageBreakBlock());
        blocks.add(new HolidayTrendWordService.SectionBlock("附录一 每日客流构成变化"));
        blocks.add(new HolidayTrendWordService.ChartBlock("每日构成", png(3), true));
 
        byte[] result = service.generate(templateBytes, 2026, blocks);
        List<String> entries = entries(result);
        assertTrue(entries.contains("word/media/image1.png"));
        assertTrue(entries.contains("word/media/image2.png"));
        assertTrue(entries.contains("word/media/image3.png"));
        assertEquals(3, entries.stream().filter(name -> name.endsWith(".png")).count());
 
        String documentXml = readEntry(result, "word/document.xml");
        assertTrue(documentXml.contains("一、总体情况"));
        assertTrue(documentXml.contains("附录一 每日客流构成变化"));
        assertTrue(documentXml.contains("客流总量"));
        assertTrue(documentXml.contains("每日构成"));
        assertTrue(!paragraphHasNumbering(documentXml, "一、总体情况"));
        assertTrue(!paragraphHasNumbering(documentXml, "附录一 每日客流构成变化"));
        assertTrue(documentXml.contains("cx=\"5000000\" cy=\"3000000\""));
        assertTrue(documentXml.contains("cx=\"4000000\" cy=\"2500000\""));
        assertEquals(2, pageBreakCount(documentXml));
 
        String rels = readEntry(result, "word/_rels/document.xml.rels");
        assertTrue(rels.contains("rId100"));
        assertTrue(rels.contains("rId102"));
    }
 
    private Path resolveTemplate() {
        Path direct = Paths.get("docs/专项统计/重要节假日/2026年十一假期全省综合运输客流量走势图.docx");
        if (Files.exists(direct)) return direct;
        return Paths.get("..", "docs", "专项统计", "重要节假日", "2026年十一假期全省综合运输客流量走势图.docx");
    }
 
    private boolean paragraphHasNumbering(String documentXml, String text) throws Exception {
        javax.xml.parsers.DocumentBuilderFactory factory =
                javax.xml.parsers.DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        org.w3c.dom.Document document = factory.newDocumentBuilder().parse(
                new java.io.ByteArrayInputStream(documentXml.getBytes("UTF-8")));
        org.w3c.dom.NodeList paragraphs = document.getElementsByTagNameNS(
                "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "p");
        for (int i = 0; i < paragraphs.getLength(); i++) {
            org.w3c.dom.Element paragraph = (org.w3c.dom.Element) paragraphs.item(i);
            StringBuilder builder = new StringBuilder();
            org.w3c.dom.NodeList texts = paragraph.getElementsByTagNameNS(
                    "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "t");
            for (int j = 0; j < texts.getLength(); j++) {
                builder.append(texts.item(j).getTextContent());
            }
            if (text.equals(builder.toString())) {
                return paragraph.getElementsByTagNameNS(
                        "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "numPr")
                        .getLength() > 0;
            }
        }
        throw new AssertionError("Paragraph not found: " + text);
    }
 
    private int pageBreakCount(String documentXml) throws Exception {
        javax.xml.parsers.DocumentBuilderFactory factory =
                javax.xml.parsers.DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        org.w3c.dom.Document document = factory.newDocumentBuilder().parse(
                new java.io.ByteArrayInputStream(documentXml.getBytes("UTF-8")));
        org.w3c.dom.NodeList breaks = document.getElementsByTagNameNS(
                "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "br");
        int count = 0;
        for (int i = 0; i < breaks.getLength(); i++) {
            org.w3c.dom.Element br = (org.w3c.dom.Element) breaks.item(i);
            if ("page".equals(br.getAttributeNS(
                    "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "type"))) {
                count++;
            }
        }
        return count;
    }
 
    private byte[] png(int seed) {
        byte[] bytes = new byte[256];
        Arrays.fill(bytes, (byte) seed);
        bytes[0] = (byte) 0x89;
        bytes[1] = 0x50;
        bytes[2] = 0x4e;
        bytes[3] = 0x47;
        return bytes;
    }
 
    private List<String> entries(byte[] zipBytes) throws Exception {
        List<String> result = new ArrayList<>();
        try (ZipInputStream input = new ZipInputStream(new ByteArrayInputStream(zipBytes))) {
            ZipEntry entry;
            while ((entry = input.getNextEntry()) != null) result.add(entry.getName());
        }
        return result;
    }
 
    private String readEntry(byte[] zipBytes, String name) throws Exception {
        try (ZipInputStream input = new ZipInputStream(new ByteArrayInputStream(zipBytes))) {
            ZipEntry entry;
            while ((entry = input.getNextEntry()) != null) {
                if (name.equals(entry.getName())) {
                    java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = input.read(buffer)) > 0) out.write(buffer, 0, length);
                    return out.toString("UTF-8");
                }
            }
        }
        return "";
    }
}