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