1 package com.acumenvelocity.ath.pagematcher;
2
3 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4 import static org.junit.jupiter.api.Assertions.assertEquals;
5 import static org.junit.jupiter.api.Assertions.assertNotNull;
6 import static org.junit.jupiter.api.Assertions.assertTrue;
7
8 import java.io.File;
9 import java.io.InputStream;
10 import java.nio.file.Files;
11 import java.nio.file.Path;
12 import java.nio.file.StandardCopyOption;
13
14 import org.apache.pdfbox.Loader;
15 import org.apache.pdfbox.pdmodel.PDDocument;
16 import org.junit.jupiter.api.AfterAll;
17 import org.junit.jupiter.api.AfterEach;
18 import org.junit.jupiter.api.BeforeAll;
19 import org.junit.jupiter.api.BeforeEach;
20 import org.junit.jupiter.api.Test;
21 import org.junit.jupiter.api.io.TempDir;
22
23 import net.sf.okapi.filters.openxml.OpenXMLFilter;
24
25 @SuppressWarnings("unused")
26 class TestDocxPageMatcher_IT {
27
28 @TempDir
29 static Path tempDir;
30
31 @BeforeAll
32 static void setUp() throws Exception {
33 DocxPageMatcher.init();
34 }
35
36 @AfterAll
37 static void tearDown() throws Exception {
38 DocxPageMatcher.done();
39 }
40
41 @Test
42 void testMatchPageCount_WithPdfOriginal_ReducesTranslationPages() throws Exception {
43
44 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
45 File docxTranslation = copyResourceToTemp("/test-translation-3pages.docx");
46
47 int originalPages = getPdfPageCount(getResourceAsStream("/test-original-2pages.pdf"));
48 int translationPagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
49
50 assertTrue(translationPagesBefore > originalPages,
51 "Translation should have more pages than original");
52
53
54 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
55
56
57 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
58 assertTrue(translationPagesAfter <= originalPages,
59 String.format("Translation pages (%d) should be <= original pages (%d)",
60 translationPagesAfter, originalPages));
61 }
62
63 @Test
64 void testMatchPageCount_WithDocxOriginal_ReducesTranslationPages() throws Exception {
65
66 InputStream docxStream = getResourceAsStream("/test-original-2pages.docx");
67 File docxTranslation = copyResourceToTemp("/test-translation-3pages.docx");
68
69 OpenXMLFilter filter = new OpenXMLFilter();
70
71 int translationPagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
72 assertTrue(translationPagesBefore > 2, "Translation should have more than 2 pages");
73
74
75 DocxPageMatcher.matchPageCount(docxStream, docxTranslation, filter);
76
77
78 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
79 assertTrue(translationPagesAfter <= 2,
80 String.format("Translation pages (%d) should be <= 2", translationPagesAfter));
81 }
82
83 @Test
84 void testMatchPageCount_TranslationAlreadyAcceptable_NoChanges() throws Exception {
85
86 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
87 File docxTranslation = copyResourceToTemp("/test-translation-2pages.docx");
88
89 long lastModifiedBefore = docxTranslation.lastModified();
90 byte[] contentBefore = Files.readAllBytes(docxTranslation.toPath());
91
92
93 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
94
95
96 byte[] contentAfter = Files.readAllBytes(docxTranslation.toPath());
97 assertArrayEquals(contentBefore, contentAfter,
98 "Document should not be modified when page count is acceptable");
99 }
100
101 @Test
102 void testMatchPageCount_TranslationHasFewerPages_NoChanges() throws Exception {
103
104 InputStream pdfStream = getResourceAsStream("/test-original-3pages.pdf");
105 File docxTranslation = copyResourceToTemp("/test-translation-2pages.docx");
106
107 byte[] contentBefore = Files.readAllBytes(docxTranslation.toPath());
108 int pagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
109
110
111 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
112
113
114 byte[] contentAfter = Files.readAllBytes(docxTranslation.toPath());
115 int pagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
116
117 assertArrayEquals(contentBefore, contentAfter,
118 "Document should not be modified when translation has fewer pages");
119 assertEquals(pagesBefore, pagesAfter, "Page count should not change");
120 }
121
122 @Test
123 void testMatchPageCount_WithUnknownFilter_NoChanges() throws Exception {
124
125 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
126 File docxTranslation = copyResourceToTemp("/test-translation-3pages.docx");
127
128 byte[] contentBefore = Files.readAllBytes(docxTranslation.toPath());
129
130
131 net.sf.okapi.common.filters.IFilter unknownFilter = new net.sf.okapi.filters.plaintext.PlainTextFilter();
132
133
134 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, unknownFilter);
135
136
137 byte[] contentAfter = Files.readAllBytes(docxTranslation.toPath());
138 assertArrayEquals(contentBefore, contentAfter,
139 "Document should not be modified with unknown filter");
140 }
141
142 @Test
143 void testMatchPageCount_LargePageDifference_ReducesGradually() throws Exception {
144
145 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
146 File docxTranslation = copyResourceToTemp("/test-translation-5pages.docx");
147
148 int translationPagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
149 assertTrue(translationPagesBefore >= 5, "Translation should have 5+ pages");
150
151
152 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
153
154
155 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
156
157 assertTrue(translationPagesAfter <= 2,
158 String.format("Translation pages (%d) should be <= 2", translationPagesAfter));
159 }
160
161 @Test
162 void testMatchPageCount_DocumentXmlFallback_WhenStylesXmlFails() throws Exception {
163
164 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
165 File docxTranslation = copyResourceToTemp("/test-translation-no-styles-3pages.docx");
166
167 int translationPagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
168
169
170 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
171
172
173 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
174 assertTrue(translationPagesAfter <= 2,
175 "Translation should be reduced even without styles.xml working");
176 }
177
178 @Test
179 void testMatchPageCount_PreservesDocumentStructure() throws Exception {
180
181 InputStream pdfStream = getResourceAsStream("/test-original-2pages.pdf");
182 File docxTranslation = copyResourceToTemp("/test-translation-formatted-3pages.docx");
183
184
185 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
186
187
188 int pagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
189 assertTrue(pagesAfter > 0, "Document should remain valid after modification");
190 assertTrue(docxTranslation.exists(), "Document file should exist");
191 assertTrue(docxTranslation.length() > 0, "Document should not be empty");
192 }
193
194 @Test
195 void testMatchPageCount_HandlesMinimumFontSize() throws Exception {
196
197 InputStream pdfStream = getResourceAsStream("/test-original-1page.pdf");
198 File docxTranslation = copyResourceToTemp("/test-translation-10pages.docx");
199
200 int translationPagesBefore = DocxPageMatcher.getDocxPageCount(docxTranslation);
201
202
203 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
204
205
206 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
207 assertTrue(translationPagesAfter < translationPagesBefore,
208 "Translation should be reduced even if target cannot be reached");
209 }
210
211 @Test
212 void testMatchPageCount_MaxIterationsLimit() throws Exception {
213
214 InputStream pdfStream = getResourceAsStream("/test-original-1page.pdf");
215 File docxTranslation = copyResourceToTemp("/test-translation-15pages.docx");
216
217
218 DocxPageMatcher.matchPageCount(pdfStream, docxTranslation, new OpenXMLFilter());
219
220
221 int translationPagesAfter = DocxPageMatcher.getDocxPageCount(docxTranslation);
222 assertTrue(translationPagesAfter > 0, "Document should remain valid");
223
224 }
225
226
227
228 private InputStream getResourceAsStream(String resourcePath) {
229 InputStream stream = getClass().getResourceAsStream(resourcePath);
230 assertNotNull(stream, "Test resource not found: " + resourcePath);
231 return stream;
232 }
233
234 private File copyResourceToTemp(String resourcePath) throws Exception {
235 InputStream inputStream = getResourceAsStream(resourcePath);
236 File tempFile = Files.createTempFile(tempDir, "test-", ".docx").toFile();
237 Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
238 inputStream.close();
239 return tempFile;
240 }
241
242 private int getPdfPageCount(InputStream pdfStream) throws Exception {
243 File tempPdf = Files.createTempFile(tempDir, "pdf-", ".pdf").toFile();
244 Files.copy(pdfStream, tempPdf.toPath(), StandardCopyOption.REPLACE_EXISTING);
245
246 try (PDDocument pdfDoc = Loader.loadPDF(tempPdf)) {
247 return pdfDoc.getNumberOfPages();
248 } finally {
249 tempPdf.delete();
250 }
251 }
252
253 }