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 java.io.File;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.lang.reflect.InvocationTargetException;
29  import java.lang.reflect.Method;
30  import java.net.MalformedURLException;
31  import java.net.URL;
32  import java.net.URLClassLoader;
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.List;
36  import java.util.Properties;
37  
38  import org.codehaus.modello.verifier.VerifierException;
39  import org.codehaus.plexus.compiler.Compiler;
40  import org.codehaus.plexus.compiler.CompilerConfiguration;
41  import org.codehaus.plexus.compiler.CompilerException;
42  import org.codehaus.plexus.compiler.CompilerMessage;
43  import org.codehaus.plexus.compiler.CompilerResult;
44  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
45  import org.codehaus.plexus.util.FileUtils;
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 extends AbstractModelloGeneratorTest {
57      private List<File> dependencies = new ArrayList<File>();
58  
59      private List<URL> urls = new ArrayList<URL>();
60  
61      private List<String> classPathElements = new ArrayList<String>();
62  
63      protected AbstractModelloJavaGeneratorTest(String name) {
64          super(name);
65      }
66  
67      protected void setUp() throws Exception {
68          super.setUp();
69  
70          FileUtils.deleteDirectory(getOutputClasses());
71  
72          assertTrue(getOutputClasses().mkdirs());
73      }
74  
75      protected File getOutputDirectory() {
76          return new File(super.getOutputDirectory(), "sources");
77      }
78  
79      protected File getOutputClasses() {
80          return new File(super.getOutputDirectory(), "classes");
81      }
82  
83      protected void addDependency(String groupId, String artifactId) {
84          File dependencyFile = getDependencyFile(groupId, artifactId);
85  
86          dependencies.add(dependencyFile);
87  
88          addClassPathFile(dependencyFile);
89      }
90  
91      protected File getDependencyFile(String groupId, String artifactId) {
92          // NOTE: dependency version is managed by project POM and not selectable by test
93  
94          String libsDir = System.getProperty("tests.lib.dir", "target/test-libs");
95          File dependencyFile = new File(libsDir, artifactId + ".jar");
96  
97          assertTrue("Can't find dependency: " + dependencyFile.getAbsolutePath(), dependencyFile.isFile());
98  
99          return dependencyFile;
100     }
101 
102     public List<File> getClasspath() {
103         return dependencies;
104     }
105 
106     protected String getModelloVersion() throws IOException {
107         Properties properties = new Properties(System.getProperties());
108 
109         if (properties.getProperty("version") == null) {
110             InputStream is = getResourceAsStream("/META-INF/maven/org.codehaus.modello/modello-test/pom.properties");
111 
112             if (is != null) {
113                 properties.load(is);
114             }
115         }
116 
117         return properties.getProperty("version");
118     }
119 
120     protected void compileGeneratedSources() throws IOException, CompilerException {
121         compileGeneratedSources(getName(), 8);
122     }
123 
124     protected void compileGeneratedSources(int minJavaSource) throws IOException, CompilerException {
125         compileGeneratedSources(getName(), minJavaSource);
126     }
127 
128     protected void compileGeneratedSources(String verifierId, int minJavaSource) throws IOException, CompilerException {
129         String runtimeVersion = System.getProperty("java.specification.version");
130         if (runtimeVersion.startsWith("1.")) {
131             runtimeVersion = runtimeVersion.substring(2);
132         }
133         int runtimeSource = Integer.parseInt(runtimeVersion);
134 
135         String javaSource;
136         // review when Java will drop support for Java 8 as source
137         if (runtimeSource <= 21) {
138             javaSource = Integer.toString(Math.max(minJavaSource, 8));
139         } else {
140             javaSource = Integer.toString(Math.max(minJavaSource, 8));
141         }
142 
143         compileGeneratedSources(verifierId, javaSource);
144     }
145 
146     private void compileGeneratedSources(String verifierId, String javaSource) throws IOException, CompilerException {
147         File generatedSources = getOutputDirectory();
148         File destinationDirectory = getOutputClasses();
149 
150         addDependency("junit", "junit");
151         addDependency("org.codehaus.plexus", "plexus-utils");
152         addDependency("org.codehaus.plexus", "plexus-xml");
153         // for plexus-xml 4
154         // addDependency("org.apache.maven", "maven-api-xml");
155         // addDependency("org.apache.maven", "maven-xml-impl");
156         addDependency("org.codehaus.modello", "modello-test");
157 
158         String[] classPathElements = new String[dependencies.size() + 2];
159         classPathElements[0] = getTestPath("target/classes");
160         classPathElements[1] = getTestPath("target/test-classes");
161 
162         for (int i = 0; i < dependencies.size(); i++) {
163             classPathElements[i + 2] = ((File) dependencies.get(i)).getAbsolutePath();
164         }
165 
166         File verifierDirectory = getTestFile("src/test/verifiers/" + verifierId);
167         String[] sourceDirectories;
168         if (verifierDirectory.canRead()) {
169             sourceDirectories = new String[] {verifierDirectory.getAbsolutePath(), generatedSources.getAbsolutePath()};
170         } else {
171             sourceDirectories = new String[] {generatedSources.getAbsolutePath()};
172         }
173 
174         Compiler compiler;
175         try {
176             compiler = lookup(Compiler.class, "javac");
177         } catch (ComponentLookupException e) {
178             throw new RuntimeException(e.getMessage(), e);
179         }
180 
181         CompilerConfiguration configuration = new CompilerConfiguration();
182         configuration.setClasspathEntries(Arrays.asList(classPathElements));
183         configuration.setSourceLocations(Arrays.asList(sourceDirectories));
184         configuration.setOutputLocation(destinationDirectory.getAbsolutePath());
185         configuration.setDebug(true);
186 
187         configuration.setSourceVersion(javaSource);
188         configuration.setTargetVersion(javaSource);
189 
190         CompilerResult result = compiler.performCompile(configuration);
191 
192         List<CompilerMessage> errors = new ArrayList<CompilerMessage>(0);
193         for (CompilerMessage compilerMessage : result.getCompilerMessages()) {
194             if (compilerMessage.isError()) {
195                 errors.add(compilerMessage);
196             }
197         }
198 
199         assertEquals("There was compilation errors: " + errors, 0, errors.size());
200     }
201 
202     /**
203      * Run a verifier class in a classloader context where compiled generated sources are available
204      *
205      * @param verifierClassName the class name of the verifier class
206      */
207     protected void verifyCompiledGeneratedSources(String verifierClassName) {
208         addClassPathFile(getOutputClasses());
209 
210         addClassPathFile(getTestFile("target/classes"));
211 
212         addClassPathFile(getTestFile("target/test-classes"));
213 
214         ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
215         URLClassLoader classLoader = URLClassLoader.newInstance(urls.toArray(new URL[urls.size()]), null);
216 
217         Thread.currentThread().setContextClassLoader(classLoader);
218 
219         try {
220             Class<?> clazz = classLoader.loadClass(verifierClassName);
221 
222             Method verify = clazz.getMethod("verify", new Class[0]);
223 
224             try {
225                 verify.invoke(clazz.getDeclaredConstructor().newInstance(), new Object[0]);
226             } catch (InvocationTargetException ex) {
227                 throw ex.getCause();
228             }
229         } catch (Throwable throwable) {
230             throw new VerifierException("Error verifying modello tests: " + throwable.getMessage(), throwable);
231         } finally {
232             Thread.currentThread().setContextClassLoader(oldCCL);
233         }
234     }
235 
236     protected void addClassPathFile(File file) {
237         assertTrue("File doesn't exists: " + file.getAbsolutePath(), file.exists());
238 
239         try {
240             urls.add(file.toURI().toURL());
241         } catch (MalformedURLException e) {
242             throw new RuntimeException(e);
243         }
244 
245         classPathElements.add(file.getAbsolutePath());
246     }
247 
248     protected void printClasspath(URLClassLoader classLoader) {
249         URL[] urls = classLoader.getURLs();
250 
251         for (URL url : urls) {
252             System.out.println(url);
253         }
254     }
255 
256     protected void assertGeneratedFileExists(String filename) {
257         File file = new File(getOutputDirectory(), filename);
258 
259         assertTrue("Missing generated file: " + file.getAbsolutePath(), file.canRead());
260 
261         assertTrue("The generated file is empty.", file.length() > 0);
262     }
263 
264     protected List<String> getClassPathElements() {
265         return classPathElements;
266     }
267 }