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