View Javadoc

1   package org.codehaus.modello;
2   
3   /*
4    * Copyright (c) 2004, Codehaus.org
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy of
7    * this software and associated documentation files (the "Software"), to deal in
8    * the Software without restriction, including without limitation the rights to
9    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10   * of the Software, and to permit persons to whom the Software is furnished to do
11   * so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  
25  import org.codehaus.modello.verifier.VerifierException;
26  import org.codehaus.plexus.compiler.Compiler;
27  import org.codehaus.plexus.compiler.CompilerConfiguration;
28  import org.codehaus.plexus.compiler.CompilerException;
29  import org.codehaus.plexus.compiler.CompilerMessage;
30  import org.codehaus.plexus.compiler.CompilerResult;
31  import org.codehaus.plexus.compiler.javac.JavacCompiler;
32  import org.codehaus.plexus.util.FileUtils;
33  
34  import java.io.File;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.lang.reflect.InvocationTargetException;
38  import java.lang.reflect.Method;
39  import java.net.MalformedURLException;
40  import java.net.URL;
41  import java.net.URLClassLoader;
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.List;
45  import java.util.Properties;
46  
47  /**
48   * Base class for unit-tests of Modello plugins that generate java code.
49   *
50   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
51   * @see #compileGeneratedSources() compileGeneratedSources() method to compile generated sources
52   * @see #verifyCompiledGeneratedSources(String) verifyCompiledGeneratedSources(String) method to run a Verifier
53   *      class against compiled generated code
54   * @see org.codehaus.modello.verifier.Verifier Verifier base class for verifiers
55   */
56  public abstract class AbstractModelloJavaGeneratorTest
57      extends AbstractModelloGeneratorTest
58  {
59      private List<File> dependencies = new ArrayList<File>();
60  
61      private List<URL> urls = new ArrayList<URL>();
62  
63      private List<String> classPathElements = new ArrayList<String>();
64  
65      protected AbstractModelloJavaGeneratorTest( String name )
66      {
67          super( name );
68      }
69  
70      protected void setUp()
71          throws Exception
72      {
73          super.setUp();
74  
75          FileUtils.deleteDirectory( getOutputClasses() );
76  
77          assertTrue( getOutputClasses().mkdirs() );
78      }
79  
80      protected File getOutputDirectory()
81      {
82          return new File( super.getOutputDirectory(), "sources" );
83      }
84  
85      protected File getOutputClasses()
86      {
87          return new File( super.getOutputDirectory(), "classes" );
88      }
89  
90      protected void addDependency( String groupId, String artifactId )
91      {
92          File dependencyFile = getDependencyFile( groupId, artifactId );
93  
94          dependencies.add( dependencyFile );
95  
96          addClassPathFile( dependencyFile );
97      }
98  
99      protected File getDependencyFile( String groupId, String artifactId )
100     {
101         // NOTE: dependency version is managed by project POM and not selectable by test
102 
103         String libsDir = System.getProperty( "tests.lib.dir", "target/test-libs" );
104         File dependencyFile = new File( libsDir, artifactId + ".jar" );
105 
106         assertTrue( "Can't find dependency: " + dependencyFile.getAbsolutePath(), dependencyFile.isFile() );
107 
108         return dependencyFile;
109     }
110 
111     public List<File> getClasspath()
112     {
113         return dependencies;
114     }
115 
116     protected String getModelloVersion()
117         throws IOException
118     {
119         Properties properties = new Properties( System.getProperties() );
120 
121         if ( properties.getProperty( "version" ) == null )
122         {
123             InputStream is = getResourceAsStream( "/META-INF/maven/org.codehaus.modello/modello-test/pom.properties" );
124 
125             if ( is != null )
126             {
127                 properties.load( is );
128             }
129         }
130 
131         return properties.getProperty( "version" );
132     }
133 
134     protected void compileGeneratedSources()
135         throws IOException, CompilerException
136     {
137         compileGeneratedSources( getName() );
138     }
139 
140     protected void compileGeneratedSources( boolean useJava5 )
141         throws IOException, CompilerException
142     {
143         compileGeneratedSources( getName(), useJava5 );
144     }
145 
146     protected void compileGeneratedSources( String verifierId )
147         throws IOException, CompilerException
148     {
149         compileGeneratedSources( verifierId, true );
150     }
151 
152     @SuppressWarnings("unchecked")
153     protected void compileGeneratedSources( String verifierId, boolean useJava5 )
154         throws IOException, CompilerException
155     {
156         File generatedSources = getOutputDirectory();
157         File destinationDirectory = getOutputClasses();
158 
159         addDependency( "junit", "junit" );
160         addDependency( "org.codehaus.plexus", "plexus-utils" );
161         addDependency( "org.codehaus.modello", "modello-test" );
162 
163         String[] classPathElements = new String[dependencies.size() + 2];
164         classPathElements[0] = getTestPath( "target/classes" );
165         classPathElements[1] = getTestPath( "target/test-classes" );
166 
167         for ( int i = 0; i < dependencies.size(); i++ )
168         {
169             classPathElements[i + 2] = ( (File) dependencies.get( i ) ).getAbsolutePath();
170         }
171 
172         File verifierDirectory = getTestFile( "src/test/verifiers/" + verifierId );
173         String[] sourceDirectories;
174         if ( verifierDirectory.canRead() )
175         {
176             sourceDirectories = new String[]{ verifierDirectory.getAbsolutePath(), generatedSources.getAbsolutePath() };
177         }
178         else
179         {
180             sourceDirectories = new String[]{ generatedSources.getAbsolutePath() };
181         }
182 
183         Compiler compiler = new JavacCompiler();
184 
185         CompilerConfiguration configuration = new CompilerConfiguration();
186         configuration.setClasspathEntries( Arrays.asList( classPathElements ) );
187         configuration.setSourceLocations( Arrays.asList( sourceDirectories ) );
188         configuration.setOutputLocation( destinationDirectory.getAbsolutePath() );
189         configuration.setDebug( true );
190         if ( useJava5 )
191         {
192             configuration.setSourceVersion( "1.5" );
193             configuration.setTargetVersion( "1.5" );
194         }
195         else
196         {
197             configuration.setSourceVersion( "1.4" );
198             configuration.setTargetVersion( "1.4" );
199         }
200 
201         CompilerResult result = compiler.performCompile( configuration );
202 
203         List<CompilerMessage> messages = result.getCompilerMessages();
204 
205         for ( CompilerMessage message : messages )
206         {
207             System.out.println(
208                 message.getFile() + "[" + message.getStartLine() + "," + message.getStartColumn() + "]: "
209                     + message.getMessage() );
210         }
211 
212         List<CompilerMessage> errors = new ArrayList<CompilerMessage>( 0 );
213         for ( CompilerMessage compilerMessage : result.getCompilerMessages() )
214         {
215             if ( compilerMessage.isError() )
216             {
217                 errors.add( compilerMessage );
218             }
219         }
220 
221         assertEquals( "There was compilation errors: " + errors, 0, errors.size() );
222     }
223 
224     /**
225      * Run a verifier class in a classloader context where compiled generated sources are available
226      *
227      * @param verifierClassName the class name of the verifier class
228      */
229     protected void verifyCompiledGeneratedSources( String verifierClassName )
230     {
231         addClassPathFile( getOutputClasses() );
232 
233         addClassPathFile( getTestFile( "target/classes" ) );
234 
235         addClassPathFile( getTestFile( "target/test-classes" ) );
236 
237         ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
238         URLClassLoader classLoader = URLClassLoader.newInstance( urls.toArray( new URL[urls.size()] ), null );
239 
240         Thread.currentThread().setContextClassLoader( classLoader );
241 
242         try
243         {
244             Class<?> clazz = classLoader.loadClass( verifierClassName );
245 
246             Method verify = clazz.getMethod( "verify", new Class[0] );
247 
248             try
249             {
250                 verify.invoke( clazz.newInstance(), new Object[0] );
251             }
252             catch ( InvocationTargetException ex )
253             {
254                 throw ex.getCause();
255             }
256         }
257         catch ( Throwable throwable )
258         {
259             throw new VerifierException( "Error verifying modello tests: " + throwable.getMessage(), throwable );
260         }
261         finally
262         {
263             Thread.currentThread().setContextClassLoader( oldCCL );
264         }
265     }
266 
267     protected void addClassPathFile( File file )
268     {
269         assertTrue( "File doesn't exists: " + file.getAbsolutePath(), file.exists() );
270 
271         try
272         {
273             urls.add( file.toURI().toURL() );
274         }
275         catch ( MalformedURLException e )
276         {
277             throw new RuntimeException( e );
278         }
279 
280         classPathElements.add( file.getAbsolutePath() );
281     }
282 
283     protected void printClasspath( URLClassLoader classLoader )
284     {
285         URL[] urls = classLoader.getURLs();
286 
287         for ( URL url : urls )
288         {
289             System.out.println( url );
290         }
291     }
292 
293     protected void assertGeneratedFileExists( String filename )
294     {
295         File file = new File( getOutputDirectory(), filename );
296 
297         assertTrue( "Missing generated file: " + file.getAbsolutePath(), file.canRead() );
298 
299         assertTrue( "The generated file is empty.", file.length() > 0 );
300     }
301 
302     /**
303      * Check if a Java 5 feature test should be skipped, since it is not supported by current test environment.
304      *
305      * @return <code>true</code> if Java 5 is not available, then feature test should be skipped by caller
306      */
307     protected boolean skipJava5FeatureTest()
308     {
309         String javaVersion = System.getProperty( "java.specification.version", "1.5" );
310 
311         if ( "1.5".compareTo( javaVersion ) > 0 )
312         {
313             System.out.println(
314                 "Skipped Java 5 feature test, not supported by current test environment (" + javaVersion + ")" );
315             return true;
316         }
317 
318         return false;
319     }
320 
321     protected List<String> getClassPathElements()
322     {
323         return classPathElements;
324     }
325 }