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