/*
* 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;
}
}