View Javadoc
1   /*
2    * Copyright 2006 Edward Kuns
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   *
14   * $Id: TestSourceGenerator.java 0000 2006-10-25 00:00:00Z ekuns $
15   */
16  package org.castor.xmlctf;
17  
18  import java.io.File;
19  import java.io.FileReader;
20  import java.io.IOException;
21  import java.net.URL;
22  import java.net.URLClassLoader;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Properties;
26  
27  import org.castor.xmlctf.compiler.CompilationException;
28  import org.castor.xmlctf.compiler.Compiler;
29  import org.castor.xmlctf.compiler.CompilerFactory;
30  import org.castor.xmlctf.compiler.OracleJavaCompiler;
31  import org.castor.xmlctf.compiler.SunJavaCompiler;
32  import org.castor.xmlctf.util.FileServices;
33  import org.exolab.castor.builder.SourceGenerator;
34  import org.exolab.castor.builder.factory.FieldInfoFactory;
35  import org.exolab.castor.tests.framework.testDescriptor.OnlySourceGenerationTest;
36  import org.exolab.castor.tests.framework.testDescriptor.SourceGeneratorTest;
37  import org.exolab.castor.tests.framework.testDescriptor.UnitTestCase;
38  import org.exolab.castor.tests.framework.testDescriptor.types.FailureStepType;
39  import org.xml.sax.InputSource;
40  
41  /**
42   * This class encapsulate all the logic needed to run the source generator by itself and then
43   * compile the file that have been generated. This class does not do anything additional. It only
44   * runs the source generator and ensures that the generated source will compile without error.
45   *
46   * @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a>
47   * @version $Revision: 0000 $ $Date: $
48   */
49  public class TestSourceGenerator extends XMLTestCase {
50  
51    /** Name of the property file to use, null if none. */
52    private final String _propertyFileName;
53    /** Name of the collection to use by default, null if we rely on the default behavior. */
54    private final String _fieldInfoFactoryName;
55    /** Name of the binding file. */
56    private final String _bindingFileName;
57    /** Array of schemas we'll process. */
58    private final String[] _schemas;
59    /** Package name for generated source. */
60    private final String _package;
61    /** Should we generate source from imported schemas? */
62    private final boolean _genFromImported;
63    /** Expected source files. */
64    private List _expectedSources;
65  
66    public TestSourceGenerator(final CastorTestCase test, final UnitTestCase unit,
67        final OnlySourceGenerationTest sourceGen) {
68      super(test, unit);
69      _propertyFileName = sourceGen.getProperty_File();
70      _fieldInfoFactoryName = sourceGen.getCollection().toString();
71      _bindingFileName = sourceGen.getBindingFile();
72      _schemas = sourceGen.getSchema();
73      _package = sourceGen.getPackage();
74      _genFromImported = unit.hasGenerateImported() && unit.getGenerateImported();
75    }
76  
77    public TestSourceGenerator(final CastorTestCase test, final UnitTestCase unit,
78        final SourceGeneratorTest sourceGen) {
79      super(test, unit);
80      _propertyFileName = sourceGen.getProperty_File();
81      _fieldInfoFactoryName = sourceGen.getCollection().toString();
82      _bindingFileName = sourceGen.getBindingFile();
83      _schemas = sourceGen.getSchema();
84      _package = sourceGen.getPackage();
85      _genFromImported = unit.hasGenerateImported() && unit.getGenerateImported();
86    }
87  
88    /**
89     * Sets up this test suite.
90     * 
91     * @throws java.lang.Exception if anything goes wrong
92     */
93    protected void setUp() throws java.lang.Exception {
94      try {
95        FileServices.copySupportFiles(_test.getTestFile(), _outputRootFile);
96      } catch (IOException e) {
97        fail("IOException copying support files " + e);
98      }
99    }
100 
101   /**
102    * Cleans up after this unit test.
103    * 
104    * @throws java.lang.Exception if anything goes wrong
105    */
106   protected void tearDown() throws java.lang.Exception {
107     // Nothing to do
108   }
109 
110   /**
111    * Runs our source generation test. Creates, configures, and executes the source generator on each
112    * schema we have to test. Compiles the generated code. Loads classes via the appropriate class
113    * loader.
114    */
115   public void runTest() {
116     if (_skip) {
117       verbose("--> Skipping the test");
118       return;
119     }
120 
121     // 1. Run the source generator
122     verbose("--> Running the source generator");
123 
124     try {
125       final SourceGenerator sourceGen = createSourceGenerator();
126 
127       for (int i = 0; i < _schemas.length; i++) {
128         String schemaName = _schemas[i];
129         File schemaFile = new File(_outputRootFile, schemaName);
130 
131         if (!schemaFile.exists()) {
132           assertNotNull("Unable to find the schema: ", schemaName);
133         }
134 
135         InputSource source = new InputSource(new FileReader(schemaFile));
136         source.setSystemId(schemaFile.getAbsolutePath());
137         sourceGen.generateSource(source, _package);
138       }
139     } catch (Exception e) {
140       if (!checkExceptionWasExpected(e, FailureStepType.SOURCE_GENERATION)) {
141         fail("Source Generator threw an Exception: " + e.getMessage());
142       }
143       return;
144     }
145 
146     if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null
147         && _failure.getFailureStep().equals(FailureStepType.SOURCE_GENERATION)) {
148       fail("Source Generator was expected to fail, but succeeded");
149       return;
150     }
151 
152     // 1a. Check that all expected files had been generated
153     checkExpectedSources();
154 
155     // 2. Compile the files generated by the source generator
156     verbose("--> Compiling the files in " + _outputRootFile);
157     try {
158       Compiler compiler = CompilerFactory.createInstance(_outputRootFile);
159       if (_unitTest.hasJavaSourceVersion()) {
160         compiler.setJavaSourceVersion(_unitTest.getJavaSourceVersion());
161       }
162       compiler.compileDirectory();
163     } catch (CompilationException e) {
164       if (!checkExceptionWasExpected(e, FailureStepType.SOURCE_COMPILATION)) {
165         fail("Compiling generated source failed: " + e.getMessage());
166       }
167       return;
168     }
169 
170     if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null
171         && _failure.getFailureStep().equals(FailureStepType.SOURCE_COMPILATION)) {
172       fail("Compilation was expected to fail, but succeeded");
173       return;
174     }
175 
176     // 3. Nest the class loader to look into the tmp dir (don't forget previous path)
177     verbose("--> Set up the class loader");
178     try {
179       URL[] urlList = {_test.getTestFile().toURI().toURL(), _outputRootFile.toURI().toURL()};
180       ClassLoader loader = new URLClassLoader(urlList, _test.getClass().getClassLoader());
181       _test.setClassLoader(loader);
182       getXMLContext().getInternalContext().setClassLoader(loader);
183     } catch (Exception e) {
184       if (!checkExceptionWasExpected(e, FailureStepType.LOAD_GENERATED_CLASSES)) {
185         fail("Unable to process the test case:" + e);
186       }
187       return;
188     }
189 
190     if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null
191         && _failure.getFailureStep().equals(FailureStepType.LOAD_GENERATED_CLASSES)) {
192       fail("Loading the generated classes was expected to fail, but succeeded");
193     }
194   }
195 
196   private void checkExpectedSources() {
197     verbose("--> Checking for the existence of all expected files in " + _outputRootFile);
198     String location = _outputRootFile.getAbsolutePath();
199 
200     boolean allFilesExist = true;
201     if (_expectedSources != null && !_expectedSources.isEmpty()) {
202       Iterator iter = _expectedSources.iterator();
203       while (iter.hasNext()) {
204         String fileName = (String) iter.next();
205         String normalizedFileName = normalizeClassName(fileName);
206         if (!new File(location + "/" + normalizedFileName + ".java").exists()) {
207           allFilesExist = false;
208         }
209       }
210     }
211 
212     if (!allFilesExist) {
213       fail("Source code generation didn't generate all expected files.");
214     }
215   }
216 
217   /**
218    * Converts a qualified class name to a file name.
219    * 
220    * @param className Qualified class name
221    * @return File name.
222    */
223   private String normalizeClassName(final String className) {
224     return className.replace('.', '/');
225   }
226 
227   /**
228    * Creates and provides initial configuration for our Source Generator.
229    *
230    * @return a new SourceGenerator configured for out test
231    * @throws IOException if any IOException occurs preparing the source generator.
232    */
233   private SourceGenerator createSourceGenerator() throws IOException {
234     // Create our source generator
235     final SourceGenerator sourceGen;
236     if (_fieldInfoFactoryName != null) {
237       FieldInfoFactory factory = new FieldInfoFactory(_fieldInfoFactoryName);
238       sourceGen = new SourceGenerator(factory);
239     } else {
240       sourceGen = new SourceGenerator();
241     }
242 
243     // Do we have a castorbuilder.properties file?
244     if (_propertyFileName != null) {
245       if (!(new File(_test.getTestFile(), _propertyFileName)).exists()) {
246         fail("Test properties file '" + _propertyFileName
247             + "' does not exist; check TestDescriptor.xml");
248       }
249       Properties prop = new Properties();
250       prop.load(_test.getClassLoader().getResourceAsStream(_propertyFileName));
251       sourceGen.setDefaultProperties(prop);
252     } else {
253       // don't forget to reset the properties
254       sourceGen.setDefaultProperties(null);
255     }
256 
257     // Do we have a binding file?
258     if (_bindingFileName != null && _bindingFileName.length() > 0) {
259       File bindingFile = new File(_outputRootFile, _bindingFileName);
260 
261       if (!bindingFile.exists()) {
262         fail("Unable to find the specified binding file: " + _bindingFileName);
263       }
264 
265       verbose("using binding file: " + bindingFile.getAbsolutePath());
266       InputSource source = new InputSource(new FileReader(bindingFile));
267       source.setSystemId(bindingFile.getAbsolutePath());
268       sourceGen.setBinding(source);
269     }
270 
271     // Final configuration of our source generator
272     sourceGen.setEqualsMethod(true);
273     sourceGen.setTestable(true);
274     sourceGen.setSuppressNonFatalWarnings(true);
275     sourceGen.setFailOnFirstError(true);
276     sourceGen.setGenerateImportedSchemas(_genFromImported);
277     sourceGen.setDestDir(_outputRootFile.getAbsolutePath());
278     return sourceGen;
279   }
280 
281   /**
282    * Sets a collection of expected source files.
283    * 
284    * @param expectedSources A collection of expected source files.
285    */
286   public void setExpectedSources(final List expectedSources) {
287     _expectedSources = expectedSources;
288   }
289 
290 }