1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.siterenderer;
20
21 import javax.inject.Inject;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.Reader;
30 import java.io.StringWriter;
31 import java.nio.charset.StandardCharsets;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.jar.JarOutputStream;
38 import java.util.zip.ZipEntry;
39
40 import org.apache.commons.io.IOUtils;
41 import org.apache.maven.artifact.Artifact;
42 import org.apache.maven.artifact.DefaultArtifact;
43 import org.apache.maven.artifact.versioning.VersionRange;
44 import org.apache.maven.doxia.Doxia;
45 import org.apache.maven.doxia.parser.ParseException;
46 import org.apache.maven.doxia.sink.Sink;
47 import org.apache.maven.doxia.site.SiteModel;
48 import org.apache.maven.doxia.site.io.xpp3.SiteXpp3Reader;
49 import org.apache.maven.doxia.siterenderer.SiteRenderingContext.SiteDirectory;
50 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
51 import org.apache.maven.doxia.xsd.AbstractXmlValidator;
52 import org.codehaus.plexus.PlexusContainer;
53 import org.codehaus.plexus.testing.PlexusTest;
54 import org.codehaus.plexus.util.FileUtils;
55 import org.codehaus.plexus.util.IOUtil;
56 import org.codehaus.plexus.util.ReaderFactory;
57 import org.codehaus.plexus.util.ReflectionUtils;
58 import org.codehaus.plexus.util.StringUtils;
59 import org.junit.jupiter.api.AfterEach;
60 import org.junit.jupiter.api.BeforeEach;
61 import org.junit.jupiter.api.Test;
62 import org.mockito.Mockito;
63 import org.xml.sax.EntityResolver;
64
65 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
66 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
67 import static org.junit.jupiter.api.Assertions.assertEquals;
68 import static org.junit.jupiter.api.Assertions.assertFalse;
69 import static org.junit.jupiter.api.Assertions.assertNotNull;
70 import static org.junit.jupiter.api.Assertions.assertTrue;
71 import static org.junit.jupiter.api.Assertions.fail;
72 import static org.mockito.Mockito.*;
73
74
75
76
77
78 @PlexusTest
79 public class DefaultSiteRendererTest {
80
81
82
83 private static final String OUTPUT = "target/output";
84
85
86
87
88 private SiteRenderer siteRenderer;
89
90 @Inject
91 private PlexusContainer container;
92
93 private File skinJar = new File(getBasedir(), "target/test-classes/skin.jar");
94
95 private File minimalSkinJar = new File(getBasedir(), "target/test-classes/minimal-skin.jar");
96
97
98
99
100 @BeforeEach
101 protected void setUp() throws Exception {
102 siteRenderer = (SiteRenderer) container.lookup(SiteRenderer.class);
103
104 InputStream skinIS = getClass().getResourceAsStream("velocity-toolmanager.vm");
105 JarOutputStream jarOS = new JarOutputStream(new FileOutputStream(skinJar));
106 try {
107 jarOS.putNextEntry(new ZipEntry("META-INF/maven/site.vm"));
108 IOUtil.copy(skinIS, jarOS);
109 jarOS.closeEntry();
110 } finally {
111 IOUtil.close(skinIS);
112 IOUtil.close(jarOS);
113 }
114
115 skinIS = new ByteArrayInputStream(
116 "<main id=\"contentBox\">$bodyContent</main>".getBytes(StandardCharsets.UTF_8));
117 jarOS = new JarOutputStream(new FileOutputStream(minimalSkinJar));
118 try {
119 jarOS.putNextEntry(new ZipEntry("META-INF/maven/site.vm"));
120 IOUtil.copy(skinIS, jarOS);
121 jarOS.closeEntry();
122 } finally {
123 IOUtil.close(skinIS);
124 IOUtil.close(jarOS);
125 }
126 }
127
128
129
130
131 @AfterEach
132 protected void tearDown() throws Exception {
133 container.release(siteRenderer);
134 }
135
136
137
138
139 @Test
140 public void testRenderExceptionMessageWhenLineNumberIsNotAvailable() throws Exception {
141 final File testBasedir = getTestFile("src/test/resources/site/xdoc");
142 final String testDocument = "head.xml";
143 final String exceptionMessage = "parse error occurred";
144
145 Doxia doxiaInstance = container.lookup(Doxia.class);
146 Doxia doxiaSpy = spy(doxiaInstance);
147 Mockito.doThrow(new ParseException(exceptionMessage))
148 .when(doxiaSpy)
149 .parse(Mockito.<Reader>any(), Mockito.anyString(), Mockito.<Sink>any(), Mockito.nullable(String.class));
150 SiteRenderer siteRenderer = container.lookup(SiteRenderer.class);
151 ReflectionUtils.setVariableValueInObject(siteRenderer, "doxia", doxiaSpy);
152
153 DocumentRenderingContext docRenderingContext =
154 new DocumentRenderingContext(testBasedir, "", testDocument, "xdoc", "", false);
155
156 try {
157 siteRenderer.renderDocument(null, docRenderingContext, new SiteRenderingContext());
158 fail("should fail with exception");
159 } catch (RendererException e) {
160 assertEquals(
161 String.format(
162 "Error parsing '%s%s%s'", testBasedir.getAbsolutePath(), File.separator, testDocument),
163 e.getMessage());
164 }
165 }
166
167
168
169
170 @Test
171 public void testRenderExceptionMessageWhenLineNumberIsAvailable() throws Exception {
172 final File testBasedir = getTestFile("src/test/resources/site/xdoc");
173 final String testDocumentName = "head.xml";
174 final String exceptionMessage = "parse error occurred";
175
176 Doxia doxiaInstance = container.lookup(Doxia.class);
177 Doxia doxiaSpy = spy(doxiaInstance);
178 Mockito.doThrow(new ParseException(exceptionMessage, 42, 36))
179 .when(doxiaSpy)
180 .parse(Mockito.<Reader>any(), Mockito.anyString(), Mockito.<Sink>any(), Mockito.nullable(String.class));
181 SiteRenderer siteRenderer = container.lookup(SiteRenderer.class);
182 ReflectionUtils.setVariableValueInObject(siteRenderer, "doxia", doxiaSpy);
183
184 DocumentRenderingContext docRenderingContext =
185 new DocumentRenderingContext(testBasedir, "", testDocumentName, "xdoc", "", false);
186
187 try {
188 siteRenderer.renderDocument(null, docRenderingContext, new SiteRenderingContext());
189 fail("should fail with exception");
190 } catch (RendererException e) {
191 assertEquals(
192 String.format(
193 "Error parsing '%s%s%s', line 42",
194 testBasedir.getAbsolutePath(), File.separator, testDocumentName),
195 e.getMessage());
196 }
197 }
198
199
200
201
202 @Test
203 public void testRender() throws Exception {
204
205 FileUtils.deleteDirectory(getTestFile(OUTPUT));
206
207
208
209
210 SiteModel siteModel =
211 new SiteXpp3Reader().read(new FileInputStream(getTestFile("src/test/resources/site/site.xml")));
212
213 SiteRenderingContext ctxt = getSiteRenderingContext(siteModel, "src/test/resources/site", false);
214 ctxt.setRootDirectory(getTestFile(""));
215 siteRenderer.render(siteRenderer.locateDocumentFiles(ctxt, true).values(), ctxt, getTestFile(OUTPUT));
216
217 ctxt = getSiteRenderingContext(siteModel, "src/test/resources/site-validate", true);
218 ctxt.setRootDirectory(getTestFile(""));
219 siteRenderer.render(siteRenderer.locateDocumentFiles(ctxt, true).values(), ctxt, getTestFile(OUTPUT));
220
221
222
223
224 verifyCdcPage();
225 verifyNestedItemsPage();
226 verifyMultipleBlock();
227 verifyMacro();
228 verifyEntitiesPage();
229 verifyJavascriptPage();
230 verifyFaqPage();
231 verifyAttributes();
232 verifyApt();
233 verifyExtensionInFilename();
234 verifyNewlines();
235
236
237
238
239 validatePages();
240 }
241
242 @Test
243 public void testExternalReport() throws Exception {
244 DocumentRenderer docRenderer = mock(DocumentRenderer.class);
245 when(docRenderer.isExternalReport()).thenReturn(true);
246 when(docRenderer.getOutputName()).thenReturn("external/index");
247 when(docRenderer.getRenderingContext())
248 .thenReturn(new DocumentRenderingContext(new File(""), "index.html", "generator:external"));
249
250 SiteRenderingContext context = new SiteRenderingContext();
251
252 siteRenderer.render(Collections.singletonList(docRenderer), context, new File("target/output"));
253
254 verify(docRenderer).renderDocument(isNull(), eq(siteRenderer), eq(context));
255 }
256
257 @Test
258 public void testVelocityToolManager() throws Exception {
259 StringWriter writer = new StringWriter();
260
261 SiteRenderingContext siteRenderingContext = new SiteRenderingContext();
262 siteRenderingContext.setSiteModel(new SiteModel());
263
264 Map<String, Object> attributes = new HashMap<>();
265
266
267
268
269
270 attributes.put("doxiaSiteRendererVersion", "1.7-bogus");
271
272 siteRenderingContext.setTemplateProperties(attributes);
273
274 siteRenderingContext.setTemplateName("org/apache/maven/doxia/siterenderer/velocity-toolmanager.vm");
275 DocumentRenderingContext docRenderingContext =
276 new DocumentRenderingContext(new File(""), "document.html", "generator");
277 SiteRendererSink sink = new SiteRendererSink(docRenderingContext);
278 siteRenderer.mergeDocumentIntoSite(writer, sink, siteRenderingContext);
279
280 String renderResult = writer.toString();
281 String expectedResult = IOUtils.toString(
282 getClass().getResourceAsStream("velocity-toolmanager.expected.txt"), StandardCharsets.UTF_8);
283 expectedResult = StringUtils.unifyLineSeparators(expectedResult);
284 assertEquals(expectedResult, renderResult);
285 }
286
287 @Test
288 public void testVelocityToolManagerForSkin() throws Exception {
289 StringWriter writer = new StringWriter();
290
291 File skinFile = skinJar;
292
293 Map<String, Object> attributes = new HashMap<>();
294
295
296
297
298
299 attributes.put("doxiaSiteRendererVersion", "1.7-bogus");
300
301 Artifact skin = new DefaultArtifact(
302 "org.group", "artifact", VersionRange.createFromVersion("1.1"), null, "jar", "", null);
303 skin.setFile(skinFile);
304 SiteRenderingContext siteRenderingContext =
305 siteRenderer.createContextForSkin(skin, attributes, new SiteModel(), "defaultitle", Locale.ROOT);
306 DocumentRenderingContext context = new DocumentRenderingContext(new File(""), "document.html", "generator");
307 SiteRendererSink sink = new SiteRendererSink(context);
308 siteRenderer.mergeDocumentIntoSite(writer, sink, siteRenderingContext);
309 String renderResult = writer.toString();
310 String expectedResult = StringUtils.unifyLineSeparators(IOUtils.toString(
311 getClass().getResourceAsStream("velocity-toolmanager.expected.txt"), StandardCharsets.UTF_8));
312 assertEquals(expectedResult, renderResult);
313 }
314
315 @Test
316 public void testMatchVersion() throws Exception {
317 DefaultSiteRenderer r = (DefaultSiteRenderer) siteRenderer;
318 assertTrue(r.matchVersion("1.7", "1.7"));
319 assertFalse(r.matchVersion("1.7", "1.8"));
320 }
321
322 private SiteRenderingContext getSiteRenderingContext(SiteModel siteModel, String siteDir, boolean validate)
323 throws RendererException, IOException {
324 File skinFile = minimalSkinJar;
325
326 final Map<String, String> attributes = new HashMap<>();
327 attributes.put("outputEncoding", "UTF-8");
328
329 Artifact skin = new DefaultArtifact(
330 "org.group", "artifact", VersionRange.createFromVersion("1.1"), null, "jar", "", null);
331 skin.setFile(skinFile);
332 SiteRenderingContext siteRenderingContext =
333 siteRenderer.createContextForSkin(skin, attributes, siteModel, "defaultTitle", Locale.ROOT);
334 siteRenderingContext.addSiteDirectory(new SiteDirectory(getTestFile(siteDir), true));
335 siteRenderingContext.setValidate(validate);
336
337 return siteRenderingContext;
338 }
339
340
341
342
343 public void verifyCdcPage() throws Exception {
344 File nestedItems = getTestFile("target/output/cdc.html");
345 assertNotNull(nestedItems);
346 assertTrue(nestedItems.exists());
347 }
348
349
350
351
352 public void verifyNestedItemsPage() throws Exception {
353 NestedItemsVerifier verifier = new NestedItemsVerifier();
354 verifier.verify("target/output/nestedItems.html");
355 }
356
357
358
359
360 public void verifyMultipleBlock() throws Exception {
361 MultipleBlockVerifier verifier = new MultipleBlockVerifier();
362 verifier.verify("target/output/multipleblock.html");
363 }
364
365
366
367
368 public void verifyMacro() throws Exception {
369 File macro = getTestFile("target/output/macro.html");
370 assertNotNull(macro);
371 assertTrue(macro.exists());
372
373 Reader reader = null;
374 try {
375 reader = ReaderFactory.newXmlReader(macro);
376 String content = IOUtil.toString(reader);
377 assertEquals(content.indexOf("</macro>"), -1);
378 } finally {
379 IOUtil.close(reader);
380 }
381 }
382
383
384
385
386 public void verifyEntitiesPage() throws Exception {
387 EntitiesVerifier verifier = new EntitiesVerifier();
388 verifier.verify("target/output/entityTest.html");
389 }
390
391
392
393
394 public void verifyJavascriptPage() throws Exception {
395 JavascriptVerifier verifier = new JavascriptVerifier();
396 verifier.verify("target/output/javascript.html");
397 }
398
399
400
401
402 public void verifyFaqPage() throws Exception {
403 FaqVerifier verifier = new FaqVerifier();
404 verifier.verify("target/output/faq.html");
405 }
406
407
408
409
410 public void verifyAttributes() throws Exception {
411 AttributesVerifier verifier = new AttributesVerifier();
412 verifier.verify("target/output/attributes.html");
413 }
414
415
416
417
418 public void verifyApt() throws Exception {
419 AbstractVerifier verifier = new AptVerifier();
420 verifier.verify("target/output/apt.html");
421
422 verifier = new CommentsVerifier();
423 verifier.verify("target/output/apt.html");
424 }
425
426
427
428
429 public void verifyExtensionInFilename() throws Exception {
430 File output = getTestFile("target/output/extension.apt.not.at.end.html");
431 assertNotNull(output);
432 assertTrue(output.exists());
433 }
434
435
436
437
438 public void verifyNewlines() throws Exception {
439
440 checkNewlines(FileUtils.fileRead(getTestFile("target/output/apt.html"), "ISO-8859-1"));
441 checkNewlines(FileUtils.fileRead(getTestFile("target/output/cdc.html"), "ISO-8859-1"));
442 checkNewlines(FileUtils.fileRead(getTestFile("target/output/interpolation.html"), "ISO-8859-1"));
443
444 checkNewlines(FileUtils.fileRead(getTestFile("target/output/faq.html"), "ISO-8859-1"));
445
446 checkNewlines(FileUtils.fileRead(getTestFile("target/output/attributes.html"), "ISO-8859-1"));
447 checkNewlines(FileUtils.fileRead(getTestFile("target/output/javascript.html"), "ISO-8859-1"));
448 checkNewlines(FileUtils.fileRead(getTestFile("target/output/head.html"), "ISO-8859-1"));
449 checkNewlines(FileUtils.fileRead(getTestFile("target/output/macro.html"), "ISO-8859-1"));
450 }
451
452 private void checkNewlines(String content) {
453 int cr = StringUtils.countMatches(content, "\r");
454 int lf = StringUtils.countMatches(content, "\n");
455 assertTrue(
456 (cr == 0) || (cr == lf), "Should contain only Windows or Unix newlines: cr = " + cr + ", lf = " + lf);
457 }
458
459
460
461
462
463
464
465 public void validatePages() throws Exception {
466 new Xhtml5ValidatorTest().validateGeneratedPages();
467 }
468
469 protected static class Xhtml5ValidatorTest extends AbstractXmlValidator {
470
471
472
473
474
475
476 public void validateGeneratedPages() throws Exception {
477 setValidate(false);
478 try {
479 testValidateFiles();
480 } finally {
481 tearDown();
482 }
483 }
484
485 private static String[] getIncludes() {
486 return new String[] {"**/*.html"};
487 }
488
489
490 protected String addNamespaces(String content) {
491 return content;
492 }
493
494
495 protected EntityResolver getEntityResolver() {
496
497 return null;
498 }
499
500
501 protected Map<String, String> getTestDocuments() throws IOException {
502 Map<String, String> testDocs = new HashMap<>();
503
504 File dir = new File(getBasedir(), "target/output");
505
506 List<String> l =
507 FileUtils.getFileNames(dir, getIncludes()[0], FileUtils.getDefaultExcludesAsString(), true);
508
509 for (String file : l) {
510 file = StringUtils.replace(file, "\\", "/");
511
512 Reader reader = ReaderFactory.newXmlReader(new File(file));
513 try {
514 testDocs.put(file, IOUtil.toString(reader));
515 } finally {
516 IOUtil.close(reader);
517 }
518 }
519
520 return testDocs;
521 }
522
523
524 @Override
525 protected boolean isFailErrorMessage(String message) {
526 return true;
527 }
528 }
529 }