/* * Copyright 2006 Edward Kuns * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * $Id: TestSourceGenerator.java 0000 2006-10-25 00:00:00Z ekuns $ */ package org.castor.xmlctf; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.castor.xmlctf.compiler.CompilationException; import org.castor.xmlctf.compiler.Compiler; import org.castor.xmlctf.compiler.SunJavaCompiler; import org.castor.xmlctf.util.FileServices; import org.exolab.castor.builder.SourceGenerator; import org.exolab.castor.builder.factory.FieldInfoFactory; import org.exolab.castor.tests.framework.testDescriptor.OnlySourceGenerationTest; import org.exolab.castor.tests.framework.testDescriptor.SourceGeneratorTest; import org.exolab.castor.tests.framework.testDescriptor.UnitTestCase; import org.exolab.castor.tests.framework.testDescriptor.types.FailureStepType; import org.xml.sax.InputSource; /** * This class encapsulate all the logic needed to run the source generator by * itself and then compile the file that have been generated. This class does * not do anything additional. It only runs the source generator and ensures * that the generated source will compile without error. * * @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a> * @version $Revision: 0000 $ $Date: $ */ public class TestSourceGenerator extends XMLTestCase { /** Name of the property file to use, null if none. */ private final String _propertyFileName; /** Name of the collection to use by default, null if we rely on the default behavior. */ private final String _fieldInfoFactoryName; /** Name of the binding file. */ private final String _bindingFileName; /** Array of schemas we'll process. */ private final String[] _schemas; /** Package name for generated source. */ private final String _package; /** Should we generate source from imported schemas? */ private final boolean _genFromImported; /** Expected source files.*/ private List _expectedSources; public TestSourceGenerator(final CastorTestCase test, final UnitTestCase unit, final OnlySourceGenerationTest sourceGen) { super(test, unit); _propertyFileName = sourceGen.getProperty_File(); _fieldInfoFactoryName = sourceGen.getCollection().toString(); _bindingFileName = sourceGen.getBindingFile(); _schemas = sourceGen.getSchema(); _package = sourceGen.getPackage(); _genFromImported = unit.hasGenerateImported() && unit.getGenerateImported(); } public TestSourceGenerator(final CastorTestCase test, final UnitTestCase unit, final SourceGeneratorTest sourceGen) { super(test, unit); _propertyFileName = sourceGen.getProperty_File(); _fieldInfoFactoryName = sourceGen.getCollection().toString(); _bindingFileName = sourceGen.getBindingFile(); _schemas = sourceGen.getSchema(); _package = sourceGen.getPackage(); _genFromImported = unit.hasGenerateImported() && unit.getGenerateImported(); } /** * Sets up this test suite. * @throws java.lang.Exception if anything goes wrong */ protected void setUp() throws java.lang.Exception { try { FileServices.copySupportFiles(_test.getTestFile(), _outputRootFile); } catch (IOException e) { fail("IOException copying support files " + e); } } /** * Cleans up after this unit test. * @throws java.lang.Exception if anything goes wrong */ protected void tearDown() throws java.lang.Exception { // Nothing to do } /** * Runs our source generation test. Creates, configures, and executes the * source generator on each schema we have to test. Compiles the generated * code. Loads classes via the appropriate class loader. */ public void runTest() { if (_skip) { verbose("--> Skipping the test"); return; } // 1. Run the source generator verbose("--> Running the source generator"); try { final SourceGenerator sourceGen = createSourceGenerator(); for (int i=0; i<_schemas.length; i++) { String schemaName = _schemas[i]; File schemaFile = new File(_outputRootFile, schemaName); if (!schemaFile.exists()) { assertNotNull("Unable to find the schema: ", schemaName); } InputSource source = new InputSource(new FileReader(schemaFile)); source.setSystemId(schemaFile.getAbsolutePath()); sourceGen.generateSource(source, _package); } } catch (Exception e) { if (!checkExceptionWasExpected(e, FailureStepType.SOURCE_GENERATION)) { fail("Source Generator threw an Exception: " + e.getMessage()); } return; } if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null && _failure.getFailureStep().equals(FailureStepType.SOURCE_GENERATION)) { fail("Source Generator was expected to fail, but succeeded"); return; } // 1a. Check that all expected files had been generated checkExpectedSources(); // 2. Compile the files generated by the source generator verbose("--> Compiling the files in " + _outputRootFile); try { Compiler compiler = new SunJavaCompiler(_outputRootFile); if (_unitTest.hasJavaSourceVersion()) { compiler.setJavaSourceVersion(_unitTest.getJavaSourceVersion()); } compiler.compileDirectory(); } catch (CompilationException e) { if (!checkExceptionWasExpected(e, FailureStepType.SOURCE_COMPILATION)) { fail("Compiling generated source failed: " + e.getMessage()); } return; } if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null && _failure.getFailureStep().equals(FailureStepType.SOURCE_COMPILATION)) { fail("Compilation was expected to fail, but succeeded"); return; } // 3. Nest the class loader to look into the tmp dir (don't forget previous path) verbose("--> Set up the class loader"); try { URL[] urlList = {_test.getTestFile().toURI().toURL(), _outputRootFile.toURI().toURL()}; ClassLoader loader = new URLClassLoader(urlList, _test.getClass().getClassLoader()); _test.setClassLoader(loader); getXMLContext().getInternalContext().setClassLoader(loader); } catch (Exception e) { if (!checkExceptionWasExpected(e, FailureStepType.LOAD_GENERATED_CLASSES)) { fail("Unable to process the test case:" + e); } return; } if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null && _failure.getFailureStep().equals(FailureStepType.LOAD_GENERATED_CLASSES)) { fail("Loading the generated classes was expected to fail, but succeeded"); } } private void checkExpectedSources() { verbose("--> Checking for the existence of all expected files in " + _outputRootFile); String location = _outputRootFile.getAbsolutePath(); boolean allFilesExist = true; if (_expectedSources != null && !_expectedSources.isEmpty()) { Iterator iter = _expectedSources.iterator(); while (iter.hasNext()) { String fileName = (String) iter.next(); String normalizedFileName = normalizeClassName(fileName); if (!new File(location + "/" + normalizedFileName + ".java").exists()) { allFilesExist = false; } } } if (!allFilesExist) { fail("Source code generation didn't generate all expected files."); } } /** * Converts a qualified class name to a file name. * @param className Qualified class name * @return File name. */ private String normalizeClassName(final String className) { return className.replace('.', '/'); } /** * Creates and provides initial configuration for our Source Generator. * * @return a new SourceGenerator configured for out test * @throws IOException * if any IOException occurs preparing the source generator. */ private SourceGenerator createSourceGenerator() throws IOException { // Create our source generator final SourceGenerator sourceGen; if (_fieldInfoFactoryName != null) { FieldInfoFactory factory = new FieldInfoFactory(_fieldInfoFactoryName); sourceGen = new SourceGenerator(factory); } else { sourceGen = new SourceGenerator(); } // Do we have a castorbuilder.properties file? if (_propertyFileName != null) { if (!(new File(_test.getTestFile(), _propertyFileName)).exists()) { fail("Test properties file '" + _propertyFileName + "' does not exist; check TestDescriptor.xml"); } Properties prop = new Properties(); prop.load(_test.getClassLoader().getResourceAsStream(_propertyFileName)); sourceGen.setDefaultProperties(prop); } else { //don't forget to reset the properties sourceGen.setDefaultProperties(null); } // Do we have a binding file? if (_bindingFileName != null && _bindingFileName.length() >0) { File bindingFile = new File(_outputRootFile, _bindingFileName); if ( !bindingFile.exists()) { fail("Unable to find the specified binding file: " + _bindingFileName); } verbose("using binding file: " + bindingFile.getAbsolutePath()); InputSource source = new InputSource(new FileReader(bindingFile)); source.setSystemId(bindingFile.getAbsolutePath()); sourceGen.setBinding(source); } // Final configuration of our source generator sourceGen.setEqualsMethod(true); sourceGen.setTestable(true); sourceGen.setSuppressNonFatalWarnings(true); sourceGen.setFailOnFirstError(true); sourceGen.setGenerateImportedSchemas(_genFromImported); sourceGen.setDestDir(_outputRootFile.getAbsolutePath()); return sourceGen; } /** * Sets a collection of expected source files. * @param expectedSources A collection of expected source files. */ public void setExpectedSources(final List expectedSources) { _expectedSources = expectedSources; } }