View Javadoc
1   package org.apache.maven.doxia.siterenderer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static org.mockito.Matchers.eq;
23  import static org.mockito.Matchers.isNull;
24  import static org.mockito.Mockito.mock;
25  import static org.mockito.Mockito.verify;
26  import static org.mockito.Mockito.when;
27  
28  import java.io.File;
29  import java.io.FileOutputStream;
30  import java.io.FileReader;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.io.OutputStream;
34  import java.io.Reader;
35  import java.io.StringWriter;
36  import java.io.Writer;
37  import java.util.Collections;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.Map;
42  import java.util.jar.JarOutputStream;
43  import java.util.zip.ZipEntry;
44  
45  import org.apache.commons.io.IOUtils;
46  import org.apache.maven.artifact.Artifact;
47  import org.apache.maven.artifact.DefaultArtifact;
48  import org.apache.maven.doxia.site.decoration.DecorationModel;
49  import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Reader;
50  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
51  import org.apache.maven.doxia.xsd.AbstractXmlValidator;
52  import org.codehaus.plexus.PlexusTestCase;
53  import org.codehaus.plexus.util.FileUtils;
54  import org.codehaus.plexus.util.IOUtil;
55  import org.codehaus.plexus.util.ReaderFactory;
56  import org.codehaus.plexus.util.StringUtils;
57  import org.xml.sax.EntityResolver;
58  
59  /**
60   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
61   * @author <a href="mailto:evenisse@codehaus.org">Emmanuel Venisse</a>
62   * @version $Id: DefaultSiteRendererTest.java 1767162 2016-10-30 14:48:28Z hboutemy $
63   */
64  public class DefaultSiteRendererTest
65      extends PlexusTestCase
66  {
67      /**
68       * All output produced by this test will go here.
69       */
70      private static final String OUTPUT = "target/output";
71  
72      /**
73       * The renderer used to produce output.
74       */
75      private Renderer renderer;
76  
77      /**
78       * The locale before executing tests.
79       */
80      private Locale oldLocale;
81  
82      private File skinJar = new File( getBasedir(), "target/test-classes/skin.jar" );
83  
84      /**
85       * @throws java.lang.Exception if something goes wrong.
86       * @see org.codehaus.plexus.PlexusTestCase#setUp()
87       */
88      @Override
89      protected void setUp()
90          throws Exception
91      {
92          super.setUp();
93  
94          renderer = (Renderer) lookup( Renderer.ROLE );
95  
96          // copy the default-site.vm and default-site-macros.vm
97          copyVm( "default-site.vm", "\n\n\n\r\n\r\n\r\n" );
98          copyVm( "default-site-macros.vm", "" );
99  
100         InputStream skinIS = this.getResourceAsStream( "velocity-toolmanager.vm" );
101         JarOutputStream jarOS = new JarOutputStream( new FileOutputStream( skinJar ) );
102         try
103         {
104             jarOS.putNextEntry( new ZipEntry( "META-INF/maven/site.vm" ) );
105             IOUtil.copy( skinIS, jarOS );
106             jarOS.closeEntry();
107         }
108         finally
109         {
110             IOUtil.close( skinIS );
111             IOUtil.close( jarOS );
112         }
113 
114         oldLocale = Locale.getDefault();
115         Locale.setDefault( Locale.ENGLISH );
116     }
117 
118     private void copyVm( String filename, String append )
119         throws IOException
120     {
121         InputStream is = this.getResourceAsStream( "/org/apache/maven/doxia/siterenderer/resources/" + filename );
122         assertNotNull( is );
123         OutputStream os = new FileOutputStream( new File( getBasedir(), "target/test-classes/" + filename ) );
124         try
125         {
126             IOUtil.copy( is, os );
127             os.write( append.getBytes( "ISO-8859-1" ) );
128         }
129         finally
130         {
131             IOUtil.close( is );
132             IOUtil.close( os );
133         }
134     }
135 
136     /**
137      * @throws java.lang.Exception if something goes wrong.
138      * @see org.codehaus.plexus.PlexusTestCase#tearDown()
139      */
140     @Override
141     protected void tearDown()
142         throws Exception
143     {
144         release( renderer );
145         super.tearDown();
146 
147         Locale.setDefault( oldLocale );
148     }
149 
150     /**
151      * @throws Exception if something goes wrong.
152      */
153     public void testRender()
154         throws Exception
155     {
156         // Safety
157         FileUtils.deleteDirectory( getTestFile( OUTPUT ) );
158 
159         // ----------------------------------------------------------------------
160         // Render the site from src/test/resources/site to OUTPUT
161         // ----------------------------------------------------------------------
162         DecorationModel decoration = new DecorationXpp3Reader()
163             .read( new FileReader( getTestFile( "src/test/resources/site/site.xml" ) ) );
164 
165         SiteRenderingContext ctxt = getSiteRenderingContext( decoration, "src/test/resources/site", false );
166         renderer.render( renderer.locateDocumentFiles( ctxt ).values(), ctxt, getTestFile( OUTPUT ) );
167 
168         ctxt = getSiteRenderingContext( decoration, "src/test/resources/site-validate", true );
169         renderer.render( renderer.locateDocumentFiles( ctxt ).values(), ctxt, getTestFile( OUTPUT ) );
170 
171         // ----------------------------------------------------------------------
172         // Verify specific pages
173         // ----------------------------------------------------------------------
174         verifyHeadPage();
175         verifyCdcPage();
176         verifyNestedItemsPage();
177         verifyMultipleBlock();
178         verifyMacro();
179         verifyEntitiesPage();
180         verifyJavascriptPage();
181         verifyFaqPage();
182         verifyAttributes();
183         verifyMisc();
184         verifyDocbookPageExists();
185         verifyApt();
186         verifyExtensionInFilename();
187         verifyNewlines();
188 
189         // ----------------------------------------------------------------------
190         // Validate the rendering pages
191         // ----------------------------------------------------------------------
192         validatePages();
193     }
194 
195     public void testExternalReport()
196         throws Exception
197     {
198         DocumentRenderer docRenderer = mock( DocumentRenderer.class );
199         when( docRenderer.isExternalReport() ).thenReturn( true );
200         when( docRenderer.getOutputName() ).thenReturn( "external/index" );
201         when( docRenderer.getRenderingContext() ).thenReturn( new RenderingContext( new File( "" ), "index.html" )  );
202 
203         SiteRenderingContext context = new SiteRenderingContext();
204 
205         renderer.render( Collections.singletonList( docRenderer ), context, new File( "target/output" ) );
206 
207         verify( docRenderer ).renderDocument( isNull( Writer.class ), eq( renderer ), eq( context ) );
208     }
209 
210     public void testVelocityToolManager()
211         throws Exception
212     {
213         StringWriter writer = new StringWriter();
214 
215         SiteRenderingContext siteRenderingContext = new SiteRenderingContext();
216         siteRenderingContext.setDecoration( new DecorationModel() );
217 
218         Map<String, Object> attributes = new HashMap<String, Object>();
219 
220         /*
221          * We need to add doxiaSiteRendererVersion manually because version property from pom.properties
222          * is not available at test time in some cases.
223          */
224         attributes.put( "doxiaSiteRendererVersion", "1.7-bogus" );
225 
226         siteRenderingContext.setTemplateProperties( attributes );
227 
228         siteRenderingContext.setTemplateName( "org/apache/maven/doxia/siterenderer/velocity-toolmanager.vm" );
229         RenderingContext context = new RenderingContext( new File( "" ), "document.html" );
230         SiteRendererSink sink = new SiteRendererSink( context );
231         renderer.generateDocument( writer, sink, siteRenderingContext );
232 
233         String renderResult = writer.toString();
234         String expectedResult = IOUtils.toString( getClass().getResourceAsStream( "velocity-toolmanager.expected.txt" ) );
235         expectedResult = StringUtils.unifyLineSeparators( expectedResult );
236         assertEquals( expectedResult, renderResult );
237     }
238 
239     public void testVelocityToolManagerForTemplate()
240         throws Exception
241     {
242         StringWriter writer = new StringWriter();
243 
244         File templateFile =
245             new File( getBasedir(), "target/test-classes/org/apache/maven/doxia/siterenderer/velocity-toolmanager.vm" );
246         Map<String, Object> attributes = new HashMap<String, Object>();
247 
248         /*
249          * We need to add doxiaSiteRendererVersion manually because version property from pom.properties
250          * is not available at test time in some cases.
251          */
252         attributes.put( "doxiaSiteRendererVersion", "1.7-bogus" );
253 
254         SiteRenderingContext siteRenderingContext =
255             renderer.createContextForTemplate( templateFile, attributes, new DecorationModel(),
256                                                "defaultWindowTitle", Locale.ENGLISH );
257         RenderingContext context = new RenderingContext( new File( "" ), "document.html" );
258         SiteRendererSink sink = new SiteRendererSink( context );
259         renderer.generateDocument( writer, sink, siteRenderingContext );
260 
261         String renderResult = writer.toString();
262         String expectedResult = IOUtils.toString( getClass().getResourceAsStream( "velocity-toolmanager.expected.txt" ) );
263         expectedResult = StringUtils.unifyLineSeparators( expectedResult );
264         assertEquals( expectedResult, renderResult );
265     }
266 
267     public void testVelocityToolManagerForSkin()
268         throws Exception
269     {
270         StringWriter writer = new StringWriter();
271 
272         File skinFile = skinJar;
273 
274         Map<String, Object> attributes = new HashMap<String, Object>();
275 
276         /*
277          * We need to add doxiaSiteRendererVersion manually because version property from pom.properties
278          * is not available at test time in some cases.
279          */
280         attributes.put( "doxiaSiteRendererVersion", "1.7-bogus" );
281 
282         Artifact skin = new DefaultArtifact( "org.group", "artifact", "1.1", null, "jar", "", null );
283         skin.setFile( skinFile );
284         SiteRenderingContext siteRenderingContext =
285             renderer.createContextForSkin( skin, attributes, new DecorationModel(), "defaultWindowTitle",
286                                            Locale.ENGLISH );
287         RenderingContext context = new RenderingContext( new File( "" ), "document.html" );
288         SiteRendererSink sink = new SiteRendererSink( context );
289         renderer.generateDocument( writer, sink, siteRenderingContext );
290         String renderResult = writer.toString();
291         String expectedResult = IOUtils.toString( getClass().getResourceAsStream( "velocity-toolmanager.expected.txt" ) );
292         expectedResult = StringUtils.unifyLineSeparators( expectedResult );
293         assertEquals( expectedResult, renderResult );
294     }
295 
296     public void testMatchVersion()
297         throws Exception
298     {
299         DefaultSiteRenderer r = (DefaultSiteRenderer) renderer;
300         assertTrue( r.matchVersion( "1.7", "1.7" ) );
301         assertFalse( r.matchVersion( "1.7", "1.8" ) );
302     }
303 
304     private SiteRenderingContext getSiteRenderingContext( DecorationModel decoration, String siteDir, boolean validate )
305     {
306         SiteRenderingContext ctxt = new SiteRenderingContext();
307         ctxt.setTemplateName( "default-site.vm" );
308         ctxt.setTemplateClassLoader( getClassLoader() );
309         ctxt.setUsingDefaultTemplate( true );
310         final Map<String, String> templateProp = new HashMap<String, String>();
311         templateProp.put( "outputEncoding", "UTF-8" );
312         ctxt.setTemplateProperties( templateProp );
313         ctxt.setDecoration( decoration );
314         ctxt.addSiteDirectory( getTestFile( siteDir ) );
315         ctxt.setValidate( validate );
316 
317         return ctxt;
318     }
319 
320     /**
321      * @throws Exception if something goes wrong.
322      */
323     public void verifyHeadPage()
324         throws Exception
325     {
326         new HeadVerifier().verify( "target/output/head.html" );
327     }
328 
329     /**
330      * @throws Exception if something goes wrong.
331      */
332     public void verifyCdcPage()
333         throws Exception
334     {
335         File nestedItems = getTestFile( "target/output/cdc.html" );
336         assertNotNull( nestedItems );
337         assertTrue( nestedItems.exists() );
338     }
339 
340     /**
341      * @throws Exception if something goes wrong.
342      */
343     public void verifyNestedItemsPage()
344         throws Exception
345     {
346         NestedItemsVerifier verifier = new NestedItemsVerifier();
347         verifier.verify( "target/output/nestedItems.html" );
348     }
349 
350     /**
351      * @throws Exception if something goes wrong.
352      */
353     public void verifyMultipleBlock()
354         throws Exception
355     {
356         MultipleBlockVerifier verifier = new MultipleBlockVerifier();
357         verifier.verify( "target/output/multipleblock.html" );
358     }
359 
360     /**
361      * @throws Exception if something goes wrong.
362      */
363     public void verifyMacro()
364         throws Exception
365     {
366         File macro = getTestFile( "target/output/macro.html" );
367         assertNotNull( macro );
368         assertTrue( macro.exists() );
369 
370         Reader reader = null;
371         try
372         {
373             reader = ReaderFactory.newXmlReader( macro );
374             String content = IOUtil.toString( reader );
375             assertEquals( content.indexOf( "</macro>" ), -1 );
376         }
377         finally
378         {
379             IOUtil.close( reader );
380         }
381     }
382 
383     /**
384      * @throws Exception if something goes wrong.
385      */
386     public void verifyEntitiesPage()
387         throws Exception
388     {
389         EntitiesVerifier verifier = new EntitiesVerifier();
390         verifier.verify( "target/output/entityTest.html" );
391     }
392 
393     /**
394      * @throws Exception if something goes wrong.
395      */
396     public void verifyJavascriptPage()
397         throws Exception
398     {
399         JavascriptVerifier verifier = new JavascriptVerifier();
400         verifier.verify( "target/output/javascript.html" );
401     }
402 
403     /**
404      * @throws Exception if something goes wrong.
405      */
406     public void verifyFaqPage()
407         throws Exception
408     {
409         FaqVerifier verifier = new FaqVerifier();
410         verifier.verify( "target/output/faq.html" );
411     }
412 
413     /**
414      * @throws Exception if something goes wrong.
415      */
416     public void verifyAttributes()
417         throws Exception
418     {
419         AttributesVerifier verifier = new AttributesVerifier();
420         verifier.verify( "target/output/attributes.html" );
421     }
422 
423     /**
424      * @throws Exception if something goes wrong.
425      */
426     public void verifyMisc()
427         throws Exception
428     {
429         AbstractVerifier verifier = new MiscVerifier();
430         verifier.verify( "target/output/misc.html" );
431 
432         verifier = new CommentsVerifier();
433         verifier.verify( "target/output/misc.html" );
434     }
435 
436     /**
437      * @throws Exception if something goes wrong.
438      */
439     public void verifyDocbookPageExists()
440         throws Exception
441     {
442         File output = getTestFile( "target/output/docbook.html" );
443         assertNotNull( output );
444         assertTrue( output.exists() );
445     }
446 
447     /**
448      * @throws Exception if something goes wrong.
449      */
450     public void verifyApt()
451         throws Exception
452     {
453         AbstractVerifier verifier = new AptVerifier();
454         verifier.verify( "target/output/apt.html" );
455 
456         verifier = new CommentsVerifier();
457         verifier.verify( "target/output/apt.html" );
458     }
459 
460     /**
461      * @throws Exception if something goes wrong.
462      */
463     public void verifyExtensionInFilename()
464         throws Exception
465     {
466         File output = getTestFile( "target/output/extension.apt.not.at.end.html" );
467         assertNotNull( output );
468         assertTrue( output.exists() );
469     }
470 
471     /**
472      * @throws Exception if something goes wrong.
473      */
474     public void verifyNewlines()
475         throws Exception
476     {
477         /* apt */
478         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/apt.html" ), "ISO-8859-1" ) );
479         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/cdc.html" ), "ISO-8859-1" ) );
480         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/interpolation.html" ), "ISO-8859-1" ) );
481         /* confluence */
482         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/confluence/anchor.html" ), "ISO-8859-1" ) );
483         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/confluence/code.html" ), "ISO-8859-1" ) );
484         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/confluence/table.html" ), "ISO-8859-1" ) );
485         /* docbook */
486         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/docbook.html" ), "ISO-8859-1" ) );
487         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/sdocbook_full.html" ), "ISO-8859-1" ) );
488         /* fml */
489         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/faq.html" ), "ISO-8859-1" ) );
490         /* xdoc */
491         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/attributes.html" ), "ISO-8859-1" ) );
492         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/javascript.html" ), "ISO-8859-1" ) );
493         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/head.html" ), "ISO-8859-1" ) );
494         checkNewlines( FileUtils.fileRead( getTestFile( "target/output/macro.html" ), "ISO-8859-1" ) );
495     }
496 
497     private void checkNewlines( String content )
498     {
499         int cr = StringUtils.countMatches( content, "\r" );
500         int lf = StringUtils.countMatches( content, "\n" );
501         assertTrue( "Should contain only Windows or Unix newlines: cr = " + cr + ", lf = " + lf, ( cr == 0 )
502             || ( cr == lf ) );
503     }
504 
505     /**
506      * Validate the generated pages.
507      *
508      * @throws Exception if something goes wrong.
509      * @since 1.1.1
510      */
511     public void validatePages()
512         throws Exception
513     {
514         new XhtmlValidatorTest().validateGeneratedPages();
515     }
516 
517     protected static class XhtmlValidatorTest
518         extends AbstractXmlValidator
519     {
520         /**
521          * Validate the generated documents.
522          *
523          * @throws Exception
524          */
525         public void validateGeneratedPages()
526             throws Exception
527         {
528             setUp();
529             testValidateFiles();
530             tearDown();
531         }
532 
533         private static String[] getIncludes()
534         {
535             return new String[] { "**/*.html" };
536         }
537 
538         /** {@inheritDoc} */
539         protected String addNamespaces( String content )
540         {
541             return content;
542         }
543 
544         /** {@inheritDoc} */
545         protected EntityResolver getEntityResolver()
546         {
547             return new XhtmlEntityResolver();
548         }
549 
550         /** {@inheritDoc} */
551         protected Map<String,String> getTestDocuments()
552             throws IOException
553         {
554             Map<String,String> testDocs = new HashMap<String,String>();
555 
556             File dir = new File( getBasedir(), "target/output" );
557 
558             List<String> l =
559                 FileUtils.getFileNames( dir, getIncludes()[0], FileUtils.getDefaultExcludesAsString(), true );
560 
561             for ( String file : l )
562             {
563                 file = StringUtils.replace( file, "\\", "/" );
564 
565                 Reader reader = ReaderFactory.newXmlReader( new File( file ) );
566                 try
567                 {
568                     testDocs.put( file, IOUtil.toString( reader ) );
569                 }
570                 finally
571                 {
572                     IOUtil.close( reader );
573                 }
574             }
575 
576             return testDocs;
577         }
578 
579         /** {@inheritDoc} */
580         @Override
581         protected boolean isFailErrorMessage( String message )
582         {
583             return true;
584         }
585     }
586 }