diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-version.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-version.ant new file mode 100644 index 000000000..922f14aee --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-version.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-xml.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-xml.ant new file mode 100644 index 000000000..91717fd16 --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/bad-xml.ant @@ -0,0 +1 @@ +this ain't xml. diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/defaults.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/defaults.ant new file mode 100644 index 000000000..b36a5c7ce --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/defaults.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/mismatched-version.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/mismatched-version.ant new file mode 100644 index 000000000..b9176c9c0 --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/mismatched-version.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/no-version.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/no-version.ant new file mode 100644 index 000000000..d1979fedf --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/no-version.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-base-dir.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-base-dir.ant new file mode 100644 index 000000000..56fe72aa4 --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-base-dir.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-default-target.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-default-target.ant new file mode 100644 index 000000000..f83f3bbeb --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-default-target.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-project-name.ant b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-project-name.ant new file mode 100644 index 000000000..a8ae1a941 --- /dev/null +++ b/proposal/myrmidon/etc/testcases/org/apache/myrmidon/components/builder/set-project-name.ant @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java index 22668c3a8..566a6af38 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/DefaultProjectBuilder.java @@ -8,8 +8,6 @@ package org.apache.myrmidon.components.builder; import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import javax.xml.parsers.SAXParser; @@ -23,13 +21,10 @@ import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.SAXConfigurationHandler; import org.apache.avalon.framework.logger.AbstractLogEnabled; -import org.apache.myrmidon.framework.conditions.AndCondition; -import org.apache.myrmidon.framework.conditions.Condition; -import org.apache.myrmidon.framework.conditions.IsSetCondition; -import org.apache.myrmidon.framework.conditions.NotCondition; import org.apache.myrmidon.interfaces.builder.ProjectBuilder; import org.apache.myrmidon.interfaces.builder.ProjectException; import org.apache.myrmidon.interfaces.model.DefaultNameValidator; +import org.apache.myrmidon.interfaces.model.Dependency; import org.apache.myrmidon.interfaces.model.Project; import org.apache.myrmidon.interfaces.model.Target; import org.apache.myrmidon.interfaces.model.TypeLib; @@ -78,31 +73,39 @@ public class DefaultProjectBuilder private Project build( final File file, final HashMap projects ) throws ProjectException { - final URL systemID = extractURL( file ); - final Project result = (Project)projects.get( systemID.toString() ); - if( null != result ) + try { - return result; - } - - // Parse the project file - final Configuration configuration = parseProject( systemID ); + // Check for cached project + final String systemID = extractURL( file ); + final Project result = (Project)projects.get( systemID ); + if( null != result ) + { + return result; + } - // Build the project model - final DefaultProject project = buildProject( file, configuration ); + // Parse the project file + final Configuration configuration = parseProject( systemID ); - projects.put( systemID.toString(), project ); + // Build the project model and add to cache + final DefaultProject project = buildProject( file, configuration ); + projects.put( systemID, project ); - //build using all top-level attributes - buildTopLevelProject( project, configuration, projects ); + // Build using all top-level attributes + buildTopLevelProject( project, configuration, projects ); - return project; + return project; + } + catch( Exception e ) + { + final String message = REZ.getString( "ant.project-build.error", file.getAbsolutePath() ); + throw new ProjectException( message, e ); + } } /** * Parses the project. */ - private Configuration parseProject( final URL systemID ) + private Configuration parseProject( final String systemID ) throws ProjectException { try @@ -117,13 +120,13 @@ public class DefaultProjectBuilder parser.setContentHandler( handler ); parser.setErrorHandler( handler ); - parser.parse( systemID.toString() ); + parser.parse( systemID ); return handler.getConfiguration(); } catch( Exception e ) { - String message = REZ.getString( "ant.project-parse.error" ); + final String message = REZ.getString( "ant.project-parse.error" ); throw new ProjectException( message, e ); } } @@ -164,7 +167,7 @@ public class DefaultProjectBuilder File baseDirectory = file.getParentFile(); if( baseDirectoryName != null ) { - baseDirectory = new File( baseDirectory, baseDirectoryName ); + baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName ); } baseDirectory = baseDirectory.getAbsoluteFile(); @@ -257,7 +260,7 @@ public class DefaultProjectBuilder { final String message = REZ.getString( "ant.malformed.version", versionString ); - throw new ProjectException( message, e ); + throw new ProjectException( message ); } } @@ -338,7 +341,7 @@ public class DefaultProjectBuilder final Configuration[] implicitTasks = (Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] ); - final Target implicitTarget = new Target( null, implicitTasks, null ); + final Target implicitTarget = new Target( implicitTasks, null ); project.setImplicitTarget( implicitTarget ); } @@ -378,26 +381,30 @@ public class DefaultProjectBuilder // Build the URL of the referenced projects final File baseDirectory = project.getBaseDirectory(); final File file = FileUtil.resolveFile( baseDirectory, location ); - final String systemID = extractURL( file ).toString(); // Locate the referenced project, building it if necessary - Project other = (Project)projects.get( systemID ); - if( null == other ) - { - other = build( file, projects ); - } + final Project other = build( file, projects ); // Add the reference project.addProject( name, other ); } - private URL extractURL( final File file ) throws ProjectException + /** + * Validates a project file name, and builds the canonical URL for it. + */ + private String extractURL( final File file ) throws ProjectException { + if( ! file.isFile() ) + { + final String message = REZ.getString( "ant.no-project-file.error" ); + throw new ProjectException( message ); + } + try { - return file.toURL(); + return file.getCanonicalFile().toURL().toString(); } - catch( MalformedURLException e ) + catch( Exception e ) { final String message = REZ.getString( "ant.project-unexpected.error" ); throw new ProjectException( message, e ); @@ -443,8 +450,6 @@ public class DefaultProjectBuilder { final String name = target.getAttribute( "name", null ); final String depends = target.getAttribute( "depends", null ); - final String ifCondition = target.getAttribute( "if", null ); - final String unlessCondition = target.getAttribute( "unless", null ); verifyTargetName( name, target ); @@ -454,10 +459,8 @@ public class DefaultProjectBuilder getLogger().debug( message ); } - final String[] dependencies = buildDependsList( depends, target ); - final Condition condition = buildCondition( ifCondition, unlessCondition ); - final Target defaultTarget = - new Target( condition, target.getChildren(), dependencies ); + final Dependency[] dependencies = buildDependsList( depends, target ); + final Target defaultTarget = new Target( target.getChildren(), dependencies ); //add target to project project.addTarget( name, defaultTarget ); @@ -485,70 +488,54 @@ public class DefaultProjectBuilder } } - private String[] buildDependsList( final String depends, final Configuration target ) + private Dependency[] buildDependsList( final String depends, final Configuration target ) throws ProjectException { - String[] dependencies = null; - //apply depends attribute - if( null != depends ) + if( null == depends ) { - final String[] elements = StringUtil.split( depends, "," ); - final ArrayList dependsList = new ArrayList(); - - for( int i = 0; i < elements.length; i++ ) - { - final String dependency = elements[ i ].trim(); - - if( 0 == dependency.length() ) - { - final String message = REZ.getString( "ant.target-bad-dependency.error", - target.getName(), - target.getLocation() ); - throw new ProjectException( message ); - } - - if( getLogger().isDebugEnabled() ) - { - final String message = REZ.getString( "ant.target-dependency.notice", dependency ); - getLogger().debug( message ); - } - - dependsList.add( dependency ); - } - - dependencies = (String[])dependsList.toArray( new String[ 0 ] ); + return null; } - return dependencies; - } - private Condition buildCondition( final String ifCondition, - final String unlessCondition ) - { - final AndCondition condition = new AndCondition(); + final String[] elements = StringUtil.split( depends, "," ); + final ArrayList dependsList = new ArrayList(); - // Add the 'if' condition - if( null != ifCondition ) + for( int i = 0; i < elements.length; i++ ) { + final String dependency = elements[ i ].trim(); + if( getLogger().isDebugEnabled() ) { - final String message = REZ.getString( "ant.target-if.notice", ifCondition ); + final String message = REZ.getString( "ant.target-dependency.notice", dependency ); getLogger().debug( message ); } - condition.add( new IsSetCondition( ifCondition ) ); - } - // Add the 'unless' condition - if( null != unlessCondition ) - { - if( getLogger().isDebugEnabled() ) + // Split project->target dependencies + final int sep = dependency.indexOf( "->" ); + final String projectName; + final String targetName; + if( sep != -1 ) { - final String message = REZ.getString( "ant.target-unless.notice", unlessCondition ); - getLogger().debug( message ); + projectName = dependency.substring( 0, sep ); + targetName = dependency.substring( sep + 2 ); + } + else + { + projectName = null; + targetName = dependency; + } + + if( targetName.length() == 0 || ( projectName != null && projectName.length() == 0 ) ) + { + final String message = REZ.getString( "ant.target-bad-dependency.error", + target.getName(), + target.getLocation() ); + throw new ProjectException( message ); } - condition.add( new NotCondition( new IsSetCondition( unlessCondition ) ) ); + + dependsList.add( new Dependency( projectName, targetName ) ); } - return condition; + return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] ); } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties index e1dc50fe1..9c73d7f79 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/builder/Resources.properties @@ -9,11 +9,10 @@ ati.attribue-unquoted.error=Expecting the value of attribute {0} to be enclosed ant.project-banner.notice=Project {0} base directory: {1}. ant.target-parse.notice=Parsing target: {0}. -ant.target-if.notice=Target if condition: {0} -ant.target-unless.notice=Target unless condition: {0} ant.target-dependency.notice=Target dependency: {0} ant.project-unexpected.error=Unexpected error building project. -ant.project-parse.error=Error parsing project. +ant.project-parse.error=Could not parse project file. +ant.project-build.error=Could not load project from "{0}". ant.no-project-element.error=Project file must be enclosed in project element. ant.unknown-toplevel-element.error=Unknown top-level element {0} at {1}. ant.project-bad-name.error=Invalid project name. @@ -26,9 +25,10 @@ ant.import-malformed.error=Malformed import at {0}. If name or type attribute is ant.target-noname.error=Discovered un-named target at {0}. ant.target-bad-name.error=Target with an invalid name at {0}. ant.target-bad-dependency.error=Discovered empty dependency in target {0} at {1}. -ant.malformed.version=Malformed version string "{0}" specified in version attribute of project. -ant.version-missing.error=Missing version attribute from project. -ant.bad-version.error=Incompatible build file version detected. Expected {0} but found {1}. +ant.malformed.version=Project has an invalid version "{0}". +ant.version-missing.error=Project has no version attribute. +ant.bad-version.error=Incompatible build file version detected. Expected version {0} but found version {1}. +ant.no-project-file.error=Project file does not exist, or is not a file. duplicate-project.error=Can not have two projects referenced in a file with the name {0}. duplicate-target.error=Can not have two targets in a file with the name {0}. diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/property/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/property/Resources.properties new file mode 100644 index 000000000..cabd0d25b --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/property/Resources.properties @@ -0,0 +1,3 @@ +#AbstractPropertyResolver +prop.mismatched-braces.error=Malformed property with mismatched }'s. +prop.missing-value.error=Unable to find "{0}" to expand during property resolution. diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java index 738c80b25..d4f6267c7 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java @@ -15,9 +15,9 @@ import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.excalibur.io.FileUtil; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; +import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; -import org.apache.avalon.framework.logger.Logger; import org.apache.myrmidon.api.TaskContext; import org.apache.myrmidon.api.TaskException; import org.apache.myrmidon.interfaces.model.DefaultNameValidator; @@ -60,7 +60,6 @@ public class DefaultTaskContext m_parent = parent; m_serviceManager = serviceManager; m_logger = logger; - //m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); } /** diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java index d500de173..01950b488 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java @@ -26,12 +26,12 @@ import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.myrmidon.api.TaskContext; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.framework.conditions.Condition; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.deployer.DeploymentException; import org.apache.myrmidon.interfaces.deployer.TypeDeployer; import org.apache.myrmidon.interfaces.executor.ExecutionFrame; import org.apache.myrmidon.interfaces.executor.Executor; +import org.apache.myrmidon.interfaces.model.Dependency; import org.apache.myrmidon.interfaces.model.Project; import org.apache.myrmidon.interfaces.model.Target; import org.apache.myrmidon.interfaces.model.TypeLib; @@ -123,9 +123,7 @@ public class DefaultWorkspace m_listenerSupport.projectStarted( project.getProjectName() ); - executeTarget( project, "", project.getImplicitTarget(), entry.getFrame() ); - - execute( project, target, entry ); + executeTarget( entry, target ); m_listenerSupport.projectFinished( project.getProjectName() ); } @@ -307,105 +305,130 @@ public class DefaultWorkspace /** * Helper method to execute a target. * - * @param project the Project - * @param targetName the name of the target - * @param entry the context + * @param entry the project to execute + * @param targetName the name of the target to execute * @exception TaskException if an error occurs */ - private void execute( final Project project, - final String targetName, - final ProjectEntry entry ) + private void executeTarget( final ProjectEntry entry, + final String targetName ) throws TaskException { - final int index = targetName.indexOf( "->" ); - if( -1 != index ) + // Locate the target + final Target target = entry.getProject().getTarget( targetName ); + if( null == target ) { - final String name = targetName.substring( 0, index ); - final String otherTargetName = targetName.substring( index + 2 ); + final String message = REZ.getString( "no-target.error", targetName ); + throw new TaskException( message ); + } - final Project otherProject = getProject( name, project ); - final ProjectEntry otherEntry = getProjectEntry( otherProject ); + executeTarget( entry, targetName, target ); + } - //Execute target in referenced project - execute( otherProject, otherTargetName, otherEntry ); + /** + * Executes a target. Does not execute the target if it has already been + * executed. Executes the dependencies of the target, before executing + * the target itself. + * + * @param name the name of target + * @param target the target + * @param entry the project in which to execute + * @exception TaskException if an error occurs + */ + private void executeTarget( final ProjectEntry entry, + final String name, + final Target target ) + throws TaskException + { + final Project project = entry.getProject(); + + // Check target state, to see if it has already been executed, and + // to check for dependency cycles + final TargetState state = entry.getTargetState( target ); + if( state == TargetState.FINISHED ) + { + // Target has been executed return; } - - final Target target = project.getTarget( targetName ); - if( null == target ) + if( state == TargetState.TRAVERSING ) { - final String message = REZ.getString( "no-target.error", targetName ); + // Cycle in target dependencies + final String message = REZ.getString( "target-dependency-cycle.error", name ); throw new TaskException( message ); } - //add target to list of targets executed - entry.completeTarget( targetName ); + // Set state to indicate this target has been started + entry.setTargetState( target, TargetState.TRAVERSING ); + + // Execute the target's dependencies + + // Implicit target first + if( target != project.getImplicitTarget() ) + { + executeTarget( entry, "", project.getImplicitTarget() ); + } - //execute all dependencies - final String[] dependencies = target.getDependencies(); + // Named dependencies + final Dependency[] dependencies = target.getDependencies(); for( int i = 0; i < dependencies.length; i++ ) { - if( !entry.isTargetCompleted( dependencies[ i ] ) ) + final Dependency dependency = dependencies[ i ]; + final String otherProjectName = dependency.getProjectName(); + if( otherProjectName != null ) + { + // Dependency in a referenced project + final Project otherProject = getProject( otherProjectName, project ); + final ProjectEntry otherEntry = getProjectEntry( otherProject ); + executeTarget( otherEntry, dependency.getTargetName() ); + } + else { - execute( project, dependencies[ i ], entry ); + // Dependency in this project + executeTarget( entry, dependency.getTargetName() ); } } - executeTarget( project, targetName, target, entry.getFrame() ); + // Now execute the target itself + executeTargetNoDeps( entry, name, target ); + + // Mark target as complete + entry.setTargetState( target, TargetState.FINISHED ); } /** - * Method to execute a particular target instance. + * Executes a target. Does not check whether the target has been + * executed already, and does not check that its dependencies have been + * executed. * - * @param name the name of target - * @param target the target - * @param frame the frame in which to execute - * @exception TaskException if an error occurs + * @param entry the project to execute the target in. + * @param name the name of the target. + * @param target the target itself */ - private void executeTarget( final Project project, - final String name, - final Target target, - final ExecutionFrame frame ) + private void executeTargetNoDeps( final ProjectEntry entry, + final String name, + final Target target ) throws TaskException { - //notify listeners + final Project project = entry.getProject(); + + // Notify listeners m_listenerSupport.targetStarted( project.getProjectName(), name ); - //check the condition associated with target. - //if it is not satisfied then skip target - final Condition condition = target.getCondition(); - if( null != condition ) + if( getLogger().isDebugEnabled() ) { - try - { - final boolean result = condition.evaluate( frame.getContext() ); - if( !result ) - { - final String message = REZ.getString( "skip-target.notice", name ); - getLogger().debug( message ); - return; - } - } - catch( final TaskException te ) - { - final String message = REZ.getString( "condition-eval.error", name ); - throw new TaskException( message, te ); - } + final String message = REZ.getString( "exec-target.notice", project.getProjectName(), name ); + getLogger().debug( message ); } - final String message = REZ.getString( "exec-target.notice", name ); - getLogger().debug( message ); - //frame.getContext().setProperty( Project.TARGET, target ); - //execute all tasks assciated with target + // Execute all tasks assciated with target final Configuration[] tasks = target.getTasks(); for( int i = 0; i < tasks.length; i++ ) { - executeTask( tasks[ i ], frame ); + executeTask( tasks[ i ], entry.getFrame() ); } - //notify listeners + // Notify listeners m_listenerSupport.targetFinished(); } @@ -421,8 +444,11 @@ public class DefaultWorkspace { final String name = task.getName(); - final String message = REZ.getString( "exec-task.notice", name ); - getLogger().debug( message ); + if( getLogger().isDebugEnabled() ) + { + final String message = REZ.getString( "exec-task.notice", name ); + getLogger().debug( message ); + } //is setting name even necessary ??? frame.getContext().setProperty( TaskContext.NAME, name ); diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java index 504e65778..1a0690613 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ProjectEntry.java @@ -7,12 +7,15 @@ */ package org.apache.myrmidon.components.workspace; -import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import org.apache.myrmidon.interfaces.executor.ExecutionFrame; import org.apache.myrmidon.interfaces.model.Project; +import org.apache.myrmidon.interfaces.model.Target; /** - * This contains detaisl for each project that is managed by ProjectManager. + * This contains details for each project that is being executed by a + * DefaultWorkspace. * * @author Peter Donald * @version $Revision$ $Date$ @@ -21,7 +24,9 @@ final class ProjectEntry { private final Project m_project; private final ExecutionFrame m_frame; - private final ArrayList m_targetsCompleted = new ArrayList(); + + /** Map from Target -> TargetState for that target. */ + private final Map m_targetState = new HashMap(); public ProjectEntry( final Project project, final ExecutionFrame frame ) @@ -40,13 +45,18 @@ final class ProjectEntry return m_frame; } - public boolean isTargetCompleted( final String target ) + public TargetState getTargetState( final Target target ) { - return m_targetsCompleted.contains( target ); + TargetState state = (TargetState)m_targetState.get( target ); + if( state == null ) + { + state = TargetState.NOT_STARTED; + } + return state; } - public void completeTarget( final String target ) + public void setTargetState( final Target target, final TargetState state ) { - m_targetsCompleted.add( target ); + m_targetState.put( target, state ); } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties index e28947723..2040dea14 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties @@ -5,10 +5,9 @@ bad-deployer-config.error=Error configuring deployer. bad-frame.error=Error setting up ExecutionFrame. no-project.error=Project {0} not found. no-target.error=Target {0} not found. -skip-target.notice=Skipping target {0} as it does not satisfy condition. -condition-eval.error=Error evaluating Condition for target {0}. -exec-target.notice=Executing target {0}. +exec-target.notice=Executing project {0}, target {1}. exec-task.notice=Executing task {0}. +target-dependency-cycle.error=Cycle in dependencies for target {0}. #DefaultTaskContext unknown-prop.error=Unknown property {0}. @@ -18,7 +17,3 @@ null-resolved-value.error=Value "{0}" resolved to null. bad-resolve.error=Unable to resolve value "{0}". bad-find-service.error=Could not find service "{0}". bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. - -#AbstractPropertyResolver -prop.mismatched-braces.error=Malformed property with mismatched }'s. -prop.missing-value.error=Unable to find "{0}" to expand during property resolution. diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/TargetState.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/TargetState.java new file mode 100644 index 000000000..1d89f30c8 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/TargetState.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.components.workspace; + +/** + * An enumerated type that represents the dependency traversal state of a + * target. + * + * @author Adam Murdoch + * @version $Revision$ $Date$ + */ +final class TargetState +{ + private TargetState() + { + } + + /** Target has not been started. */ + public final static TargetState NOT_STARTED = new TargetState(); + + /** + * Target has been started, and the dependencies of the target are being + * traversed. + */ + public final static TargetState TRAVERSING = new TargetState(); + + /** Target has been completed. */ + public final static TargetState FINISHED = new TargetState(); +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java index 0c4a4df38..ad5b49c9b 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/builder/ProjectBuilder.java @@ -23,7 +23,7 @@ public interface ProjectBuilder /** * build a project from source. * - * @param source the source + * @param source the project file path. * @return the constructed Project * @exception ProjectException if an error occurs */ diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Dependency.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Dependency.java new file mode 100644 index 000000000..8c2ff9d3e --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Dependency.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.interfaces.model; + +/** + * A dependency for a target. + * + * @author Adam Murdoch + * @version $Revision$ $Date$ + */ +public class Dependency +{ + private final String m_projectName; + private final String m_targetName; + + public Dependency( final String projectName, final String targetName ) + { + m_projectName = projectName; + m_targetName = targetName; + } + + public String getProjectName() + { + return m_projectName; + } + + public String getTargetName() + { + return m_targetName; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java index 541a4aac7..1dbaab8d0 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/model/Target.java @@ -9,7 +9,6 @@ package org.apache.myrmidon.interfaces.model; import java.util.ArrayList; import org.apache.avalon.framework.configuration.Configuration; -import org.apache.myrmidon.framework.conditions.Condition; /** * Targets in build file. @@ -21,19 +20,13 @@ public class Target { private final ArrayList m_dependencies = new ArrayList(); private final ArrayList m_tasks = new ArrayList(); - private final Condition m_condition; /** - * Constructor taking condition for target. - * - * @param condition the condition + * Constructs a target. */ - public Target( final Condition condition, - final Configuration[] tasks, - final String[] dependencies ) + public Target( final Configuration[] tasks, + final Dependency[] dependencies ) { - m_condition = condition; - for( int i = 0; i < tasks.length; i++ ) { m_tasks.add( tasks[ i ] ); @@ -48,24 +41,14 @@ public class Target } } - /** - * Get condition under which target is executed. - * - * @return the condition for target or null - */ - public final Condition getCondition() - { - return m_condition; - } - /** * Get dependencies of target * * @return the dependency list */ - public final String[] getDependencies() + public final Dependency[] getDependencies() { - return (String[])m_dependencies.toArray( new String[ 0 ] ); + return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] ); } /** diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java index 1b93bbe03..a8e69346c 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java @@ -89,6 +89,14 @@ public abstract class AbstractFileSystemTest m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; } + /** + * Cleans-up test. + */ + protected void tearDown() throws Exception + { + m_manager.close(); + } + /** * Tests resolution of absolute URI. */ diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java index eb3240a19..36c63d613 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java @@ -11,13 +11,8 @@ import java.io.File; import java.io.IOException; import junit.framework.TestCase; import org.apache.avalon.framework.ExceptionUtil; -import org.apache.avalon.framework.logger.LogKitLogger; import org.apache.avalon.framework.logger.Logger; -import org.apache.log.Hierarchy; -import org.apache.log.LogTarget; -import org.apache.log.Priority; -import org.apache.log.format.PatternFormatter; -import org.apache.log.output.io.StreamTarget; +import org.apache.myrmidon.frontends.BasicLogger; /** * A base class for Myrmidon tests. Provides utility methods for locating @@ -30,8 +25,7 @@ public abstract class AbstractMyrmidonTest { private final File m_testBaseDir; private final File m_baseDir; - - private final static String PATTERN = "[%8.8{category}] %{message}\\n%{throwable}"; + private Logger m_logger; public AbstractMyrmidonTest( String name ) { @@ -49,10 +43,39 @@ public abstract class AbstractMyrmidonTest * Locates a test resource, and asserts that the resource exists */ protected File getTestResource( final String name ) + { + return getTestResource( name, true ); + } + + /** + * Locates a test resource. + */ + protected File getTestResource( final String name, final boolean mustExist ) { File file = new File( m_testBaseDir, name ); file = getCanonicalFile( file ); - assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); + if( mustExist ) + { + assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); + } + else + { + assertTrue( "Test file \"" + file + "\" should not exist.", !file.exists() ); + } + + return file; + } + + /** + * Locates a test directory, creating it if it does not exist. + */ + protected File getTestDirectory( final String name ) + { + File file = new File( m_testBaseDir, name ); + file = getCanonicalFile( file ); + + assertTrue( "Test directory \"" + file + "\" does not exist or is not a directory.", + file.isDirectory() || file.mkdirs() ); return file; } @@ -83,18 +106,13 @@ public abstract class AbstractMyrmidonTest /** * Creates a logger. */ - protected Logger createLogger() + protected Logger getLogger() { - // Setup a logger - final Priority priority = Priority.WARN; - final org.apache.log.Logger targetLogger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" ); - - final PatternFormatter formatter = new PatternFormatter( PATTERN ); - final StreamTarget target = new StreamTarget( System.out, formatter ); - targetLogger.setLogTargets( new LogTarget[]{target} ); - targetLogger.setPriority( priority ); - - return new LogKitLogger( targetLogger ); + if( m_logger == null ) + { + m_logger = new BasicLogger( "[test]", BasicLogger.LEVEL_WARN ); + } + return m_logger; } /** @@ -105,6 +123,12 @@ public abstract class AbstractMyrmidonTest */ protected void assertSameMessage( final String[] messages, final Throwable throwable ) { + //System.out.println( "exception:" ); + //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) ) + //{ + // System.out.println( " " + t.getMessage() ); + //} + Throwable current = throwable; for( int i = 0; i < messages.length; i++ ) { @@ -125,7 +149,7 @@ public abstract class AbstractMyrmidonTest */ protected void assertSameMessage( final String message, final Throwable throwable ) { - assertEquals( message, throwable.getMessage() ); + assertSameMessage( new String[] { message }, throwable ); } /** diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java index ef6f324c6..371e341da 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractProjectTest.java @@ -54,7 +54,7 @@ public class AbstractProjectTest // Need to set the context classloader - The default embeddor uses it Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); - final Logger logger = createLogger(); + final Logger logger = getLogger(); m_embeddor = new DefaultEmbeddor(); m_embeddor.enableLogging( logger ); diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java index 2dad31090..244c6a02d 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java @@ -14,7 +14,6 @@ import org.apache.aut.converter.Converter; import org.apache.avalon.framework.logger.LogEnabled; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.service.DefaultServiceManager; -import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.myrmidon.AbstractMyrmidonTest; @@ -24,20 +23,19 @@ import org.apache.myrmidon.components.converter.DefaultConverterRegistry; import org.apache.myrmidon.components.converter.DefaultMasterConverter; import org.apache.myrmidon.components.deployer.DefaultDeployer; import org.apache.myrmidon.components.extensions.DefaultExtensionManager; +import org.apache.myrmidon.components.property.DefaultPropertyResolver; import org.apache.myrmidon.components.role.DefaultRoleManager; import org.apache.myrmidon.components.type.DefaultTypeManager; -import org.apache.myrmidon.components.property.DefaultPropertyResolver; import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; import org.apache.myrmidon.interfaces.configurer.Configurer; import org.apache.myrmidon.interfaces.converter.ConverterRegistry; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.extensions.ExtensionManager; +import org.apache.myrmidon.interfaces.property.PropertyResolver; import org.apache.myrmidon.interfaces.role.RoleInfo; import org.apache.myrmidon.interfaces.role.RoleManager; import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; -import org.apache.myrmidon.interfaces.type.TypeException; import org.apache.myrmidon.interfaces.type.TypeManager; -import org.apache.myrmidon.interfaces.property.PropertyResolver; /** * A base class for tests for the default components. @@ -48,7 +46,6 @@ public abstract class AbstractComponentTest extends AbstractMyrmidonTest { private DefaultServiceManager m_serviceManager; - private Logger m_logger; public AbstractComponentTest( final String name ) { @@ -58,95 +55,85 @@ public abstract class AbstractComponentTest /** * Returns the component manager containing the components to test. */ - protected final ServiceManager getServiceManager() - { - return m_serviceManager; - } - - protected final Logger getLogger() + protected final ServiceManager getServiceManager() throws Exception { - return m_logger; - } - - /** - * Returns the type manager. - */ - protected TypeManager getTypeManager() - throws ServiceException - { - return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); - } - - /** - * Setup the test case - prepares the set of components. - */ - protected void setUp() - throws Exception - { - m_logger = createLogger(); + if( m_serviceManager == null ) + { + Logger logger = getLogger(); - // Create the components - m_serviceManager = new DefaultServiceManager(); - List components = new ArrayList(); + // Create the components + m_serviceManager = new DefaultServiceManager(); + List components = new ArrayList(); - Object component = new DefaultMasterConverter(); - m_serviceManager.put( Converter.ROLE, component ); - components.add( component ); + Object component = new DefaultMasterConverter(); + m_serviceManager.put( Converter.ROLE, component ); + components.add( component ); - component = new DefaultConverterRegistry(); - m_serviceManager.put( ConverterRegistry.ROLE, component ); - components.add( component ); + component = new DefaultConverterRegistry(); + m_serviceManager.put( ConverterRegistry.ROLE, component ); + components.add( component ); - component = new DefaultTypeManager(); - m_serviceManager.put( TypeManager.ROLE, component ); - components.add( component ); + component = new DefaultTypeManager(); + m_serviceManager.put( TypeManager.ROLE, component ); + components.add( component ); - component = new DefaultConfigurer(); - m_serviceManager.put( Configurer.ROLE, component ); - components.add( component ); + component = new DefaultConfigurer(); + m_serviceManager.put( Configurer.ROLE, component ); + components.add( component ); - component = new DefaultDeployer(); - m_serviceManager.put( Deployer.ROLE, component ); - components.add( component ); + component = new DefaultDeployer(); + m_serviceManager.put( Deployer.ROLE, component ); + components.add( component ); - final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); - classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); - m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); - components.add( classLoaderMgr ); + final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); + classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); + m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); + components.add( classLoaderMgr ); - component = new DefaultExtensionManager(); - m_serviceManager.put( ExtensionManager.ROLE, component ); - components.add( component ); + component = new DefaultExtensionManager(); + m_serviceManager.put( ExtensionManager.ROLE, component ); + components.add( component ); - component = new DefaultRoleManager(); - m_serviceManager.put( RoleManager.ROLE, component ); - components.add( component ); + component = new DefaultRoleManager(); + m_serviceManager.put( RoleManager.ROLE, component ); + components.add( component ); - component = new DefaultPropertyResolver(); - m_serviceManager.put( PropertyResolver.ROLE, component ); - components.add( component ); + component = new DefaultPropertyResolver(); + m_serviceManager.put( PropertyResolver.ROLE, component ); + components.add( component ); - // Log enable the components - for( Iterator iterator = components.iterator(); iterator.hasNext(); ) - { - Object obj = iterator.next(); - if( obj instanceof LogEnabled ) + // Log enable the components + for( Iterator iterator = components.iterator(); iterator.hasNext(); ) { - final LogEnabled logEnabled = (LogEnabled)obj; - logEnabled.enableLogging( m_logger ); + Object obj = iterator.next(); + if( obj instanceof LogEnabled ) + { + final LogEnabled logEnabled = (LogEnabled)obj; + logEnabled.enableLogging( logger ); + } } - } - // Compose the components - for( Iterator iterator = components.iterator(); iterator.hasNext(); ) - { - Object obj = iterator.next(); - if( obj instanceof Serviceable ) + // Compose the components + for( Iterator iterator = components.iterator(); iterator.hasNext(); ) { - final Serviceable serviceable = (Serviceable)obj; - serviceable.service( m_serviceManager ); + Object obj = iterator.next(); + if( obj instanceof Serviceable ) + { + final Serviceable serviceable = (Serviceable)obj; + serviceable.service( m_serviceManager ); + } } } + return m_serviceManager; + } + + /** + * Returns the type manager. + */ + protected TypeManager getTypeManager() + throws Exception + { + return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); } /** @@ -179,7 +166,7 @@ public abstract class AbstractComponentTest protected void registerConverter( final Class converterClass, final Class sourceClass, final Class destClass ) - throws ServiceException, TypeException + throws Exception { ConverterRegistry converterRegistry = (ConverterRegistry)getServiceManager().lookup( ConverterRegistry.ROLE ); converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java index dfbcbcd94..00c706cca 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java @@ -8,9 +8,13 @@ package org.apache.myrmidon.components.builder; import java.io.File; +import java.util.Arrays; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.excalibur.io.FileUtil; import org.apache.myrmidon.AbstractMyrmidonTest; +import org.apache.myrmidon.interfaces.builder.ProjectException; +import org.apache.myrmidon.interfaces.model.Project; /** * Test cases for {@link DefaultProjectBuilder}. @@ -22,7 +26,7 @@ public class DefaultProjectBuilderTest extends AbstractMyrmidonTest { private final static Resources REZ - = ResourceManager.getPackageResources( DefaultProjectBuilder.class ); + = ResourceManager.getPackageResources( DefaultProjectBuilderTest.class ); private DefaultProjectBuilder m_builder; @@ -35,11 +39,227 @@ public class DefaultProjectBuilderTest { super.setUp(); m_builder = new DefaultProjectBuilder(); - m_builder.enableLogging( createLogger() ); + m_builder.enableLogging( getLogger() ); } /** - * Test validation of project and target names. + * Creates a project, with default values set. + */ + private DefaultProject createProject( final File projFile ) + { + final DefaultProject project = new DefaultProject(); + project.setProjectName( FileUtil.removeExtension( projFile.getName() ) ); + project.setBaseDirectory( getTestDirectory( "." ) ); + project.setDefaultTargetName( "main" ); + return project; + } + + /** + * Tests bad project file name. + */ + public void testProjectFileName() throws Exception + { + // Test with a file that does not exist + File projFile = getTestResource( "unknown.ant", false ); + + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.no-project-file.error" ) + }; + assertSameMessage( messages, e ); + } + + // Test with a directory + projFile = getTestDirectory( "some-dir" ); + + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.no-project-file.error" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Tests error reporting when the project file contains badly formed XML. + */ + public void testBadlyFormedFile() throws Exception + { + final File projFile = getTestResource( "bad-xml.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.project-parse.error" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Tests building a project with default values for project name, base dir + * and default target. + */ + public void testDefaults() throws Exception + { + // Build project + final File projFile = getTestResource( "defaults.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the project name. + */ + public void testProjectName() throws Exception + { + // Build project + final File projFile = getTestResource( "set-project-name.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + expected.setProjectName( "some-project" ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the base directory. + */ + public void testBaseDirectory() throws Exception + { + // Build project + final File projFile = getTestResource( "set-base-dir.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + final File baseDir = getTestDirectory( "other-base-dir" ); + expected.setBaseDirectory( baseDir ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the default target name. + */ + public void testDefaultTarget() throws Exception + { + // Build project + final File projFile = getTestResource( "set-default-target.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + expected.setDefaultTargetName( "some-target" ); + assertSameProject( expected, project ); + } + + /** + * Tests missing, invalid and incompatible project version. + */ + public void testProjectVersion() throws Exception + { + // No version + File projFile = getTestResource( "no-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.version-missing.error" ) + }; + assertSameMessage( messages, e ); + } + + // Badly formed version + projFile = getTestResource( "bad-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.malformed.version", "ant2" ) + }; + assertSameMessage( messages, e ); + } + + // Incompatible version + projFile = getTestResource( "mismatched-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.bad-version.error", "2.0.0", "1.0.2" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Asserts that 2 projects are identical. + */ + protected void assertSameProject( final Project expected, + final Project project ) + { + assertEquals( expected.getProjectName(), project.getProjectName() ); + assertEquals( expected.getBaseDirectory(), project.getBaseDirectory() ); + assertEquals( expected.getDefaultTargetName(), project.getDefaultTargetName() ); + + // TODO - make sure each of the projects are the same + assertTrue( Arrays.equals( expected.getProjectNames(), project.getProjectNames() ) ); + + // TODO - make sure the implicit targets are the same + + // TODO - make sure each of the targets are the same + assertTrue( Arrays.equals( expected.getTargetNames(), project.getTargetNames() ) ); + + // TODO - implement TypeLib.equals(), or use a comparator + assertTrue( Arrays.equals( expected.getTypeLibs(), project.getTypeLibs() ) ); + } + + /** + * Tests validation of project and target names. */ public void testNameValidation() throws Exception { @@ -52,7 +272,12 @@ public class DefaultProjectBuilderTest } catch( Exception e ) { - assertSameMessage( REZ.getString( "ant.project-bad-name.error" ), e ); + final String[] messages = + { + REZ.getString( "ant.project-build.error", badProjectFile.getAbsolutePath() ), + REZ.getString( "ant.project-bad-name.error" ) + }; + assertSameMessage( messages, e ); } // Check bad target name @@ -64,7 +289,13 @@ public class DefaultProjectBuilderTest } catch( Exception e ) { - // TODO - check error message + final String[] messages = + { + REZ.getString( "ant.project-build.error", badTargetFile.getAbsolutePath() ), + // TODO - check error message + null + }; + assertSameMessage( messages, e ); } } } diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java similarity index 70% rename from proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java rename to proposal/myrmidon/src/test/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java index e92675b83..9e79a0d2b 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java @@ -5,53 +5,51 @@ * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ -package org.apache.myrmidon.components.workspace; +package org.apache.myrmidon.components.property; import java.io.File; import java.util.Date; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.context.Context; +import org.apache.myrmidon.AbstractMyrmidonTest; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.components.AbstractComponentTest; -import org.apache.myrmidon.components.property.DefaultPropertyResolver; +import org.apache.myrmidon.components.workspace.DefaultTaskContext; import org.apache.myrmidon.interfaces.property.PropertyResolver; /** - * Functional tests for {@link DefaultPropertyResolver}. + * General-purpose property resolver test cases. * - * @author Darrell DeBoer + * @author Adam Murdoch * @version $Revision$ $Date$ */ -public class DefaultPropertyResolverTest - extends AbstractComponentTest +public abstract class AbstractPropertyResolverTest + extends AbstractMyrmidonTest { protected final static Resources REZ - = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); + = ResourceManager.getPackageResources( AbstractPropertyResolverTest.class ); protected PropertyResolver m_resolver; protected DefaultTaskContext m_context; - public DefaultPropertyResolverTest( String name ) + public AbstractPropertyResolverTest( String name ) { super( name ); } protected void setUp() throws Exception { - super.setUp(); - m_resolver = createResolver(); - m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); + m_context = new DefaultTaskContext( null, null, getLogger() ); m_context.setProperty( "intProp", new Integer( 333 ) ); m_context.setProperty( "stringProp", "String property" ); } - protected PropertyResolver createResolver() - { - return new DefaultPropertyResolver(); - } + /** + * Creates the resolver to test. + */ + protected abstract PropertyResolver createResolver(); /** * Test property resolution with various different typed properties. @@ -73,7 +71,7 @@ public class DefaultPropertyResolverTest throws Exception { m_context.setProperty( "typedProp", propObject ); - String propString = propObject.toString(); + final String propString = propObject.toString(); doTestResolution( "${typedProp}", propObject, m_context ); doTestResolution( "${typedProp} with following text", @@ -96,23 +94,6 @@ public class DefaultPropertyResolverTest doTestResolution( "before ${prop2} between ${prop1} after", "before value2 between value1 after", m_context ); doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); - - } - - /** - * Tests handing undefined property. - */ - public void testUndefinedProp() throws Exception - { - String undefinedProp = "undefinedProperty"; - doTestFailure( "${" + undefinedProp + "}", - REZ.getString( "prop.missing-value.error", undefinedProp ), - m_context ); - - //TODO - "" should be disallowed as a property name - doTestFailure( "${}", - REZ.getString( "prop.missing-value.error", "" ), - m_context ); } /** @@ -131,18 +112,17 @@ public class DefaultPropertyResolverTest /* TODO - need to handle these cases. */ // testFailure( "${bad${}", "", m_context ); // testFailure( "${ }", "", m_context ); - } /** * Resolves the property using the supplied context, and checks the result. */ - protected void doTestResolution( String value, - Object expected, - Context context ) + protected void doTestResolution( final String value, + final Object expected, + final Context context ) throws Exception { - Object resolved = m_resolver.resolveProperties( value, context ); + final Object resolved = m_resolver.resolveProperties( value, context ); assertEquals( expected, resolved ); } @@ -151,9 +131,9 @@ public class DefaultPropertyResolverTest * Attempts to resolve the value using the supplied context, expecting to * fail with the supplied error message. */ - protected void doTestFailure( String value, - String expectedErrorMessage, - Context context ) + protected void doTestFailure( final String value, + final String expectedErrorMessage, + final Context context ) { try { diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java similarity index 77% rename from proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java rename to proposal/myrmidon/src/test/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java index ae5cbabdf..a0779291f 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java @@ -5,19 +5,18 @@ * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ -package org.apache.myrmidon.components.workspace; +package org.apache.myrmidon.components.property; import org.apache.myrmidon.interfaces.property.PropertyResolver; -import org.apache.myrmidon.components.property.ClassicPropertyResolver; /** - * A test for {@link ClassicPropertyResolver} + * A test for {@link ClassicPropertyResolver}. * * @author Darrell DeBoer * @version $Revision$ $Date$ */ public class ClassicPropertyResolverTest - extends DefaultPropertyResolverTest + extends AbstractPropertyResolverTest { public ClassicPropertyResolverTest( String name ) { @@ -34,8 +33,7 @@ public class ClassicPropertyResolverTest */ public void testUndefinedProp() throws Exception { - String undefinedProp = "undefinedProperty"; - + final String undefinedProp = "undefinedProperty"; final String propRef = "${" + undefinedProp + "}"; doTestResolution( propRef, propRef, m_context ); } diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java new file mode 100644 index 000000000..4d1f2198d --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.components.property; + +import org.apache.myrmidon.interfaces.property.PropertyResolver; + +/** + * Functional tests for {@link DefaultPropertyResolver}. + * + * @author Darrell DeBoer + * @version $Revision$ $Date$ + */ +public class DefaultPropertyResolverTest + extends AbstractPropertyResolverTest +{ + public DefaultPropertyResolverTest( String name ) + { + super( name ); + } + + protected PropertyResolver createResolver() + { + return new DefaultPropertyResolver(); + } + + /** + * Tests handing undefined property. + */ + public void testUndefinedProp() throws Exception + { + final String undefinedProp = "undefinedProperty"; + doTestFailure( "${" + undefinedProp + "}", + REZ.getString( "prop.missing-value.error", undefinedProp ), + m_context ); + + //TODO - "" should be disallowed as a property name + doTestFailure( "${}", + REZ.getString( "prop.missing-value.error", "" ), + m_context ); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java index 8ce1fb3cb..c2b69bdff 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java @@ -44,11 +44,9 @@ public class InstantiatingServiceManagerTest protected void setUp() throws Exception { - super.setUp(); - // Set-up the service manager m_serviceManager = new InstantiatingServiceManager(); - m_serviceManager.enableLogging( createLogger() ); + m_serviceManager.enableLogging( getLogger() ); m_serviceManager.service( getServiceManager() ); m_serviceManager.parameterize( m_parameters ); } diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java index 1b93bbe03..a8e69346c 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java @@ -89,6 +89,14 @@ public abstract class AbstractFileSystemTest m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; } + /** + * Cleans-up test. + */ + protected void tearDown() throws Exception + { + m_manager.close(); + } + /** * Tests resolution of absolute URI. */ diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java index eb3240a19..36c63d613 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java @@ -11,13 +11,8 @@ import java.io.File; import java.io.IOException; import junit.framework.TestCase; import org.apache.avalon.framework.ExceptionUtil; -import org.apache.avalon.framework.logger.LogKitLogger; import org.apache.avalon.framework.logger.Logger; -import org.apache.log.Hierarchy; -import org.apache.log.LogTarget; -import org.apache.log.Priority; -import org.apache.log.format.PatternFormatter; -import org.apache.log.output.io.StreamTarget; +import org.apache.myrmidon.frontends.BasicLogger; /** * A base class for Myrmidon tests. Provides utility methods for locating @@ -30,8 +25,7 @@ public abstract class AbstractMyrmidonTest { private final File m_testBaseDir; private final File m_baseDir; - - private final static String PATTERN = "[%8.8{category}] %{message}\\n%{throwable}"; + private Logger m_logger; public AbstractMyrmidonTest( String name ) { @@ -49,10 +43,39 @@ public abstract class AbstractMyrmidonTest * Locates a test resource, and asserts that the resource exists */ protected File getTestResource( final String name ) + { + return getTestResource( name, true ); + } + + /** + * Locates a test resource. + */ + protected File getTestResource( final String name, final boolean mustExist ) { File file = new File( m_testBaseDir, name ); file = getCanonicalFile( file ); - assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); + if( mustExist ) + { + assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); + } + else + { + assertTrue( "Test file \"" + file + "\" should not exist.", !file.exists() ); + } + + return file; + } + + /** + * Locates a test directory, creating it if it does not exist. + */ + protected File getTestDirectory( final String name ) + { + File file = new File( m_testBaseDir, name ); + file = getCanonicalFile( file ); + + assertTrue( "Test directory \"" + file + "\" does not exist or is not a directory.", + file.isDirectory() || file.mkdirs() ); return file; } @@ -83,18 +106,13 @@ public abstract class AbstractMyrmidonTest /** * Creates a logger. */ - protected Logger createLogger() + protected Logger getLogger() { - // Setup a logger - final Priority priority = Priority.WARN; - final org.apache.log.Logger targetLogger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" ); - - final PatternFormatter formatter = new PatternFormatter( PATTERN ); - final StreamTarget target = new StreamTarget( System.out, formatter ); - targetLogger.setLogTargets( new LogTarget[]{target} ); - targetLogger.setPriority( priority ); - - return new LogKitLogger( targetLogger ); + if( m_logger == null ) + { + m_logger = new BasicLogger( "[test]", BasicLogger.LEVEL_WARN ); + } + return m_logger; } /** @@ -105,6 +123,12 @@ public abstract class AbstractMyrmidonTest */ protected void assertSameMessage( final String[] messages, final Throwable throwable ) { + //System.out.println( "exception:" ); + //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) ) + //{ + // System.out.println( " " + t.getMessage() ); + //} + Throwable current = throwable; for( int i = 0; i < messages.length; i++ ) { @@ -125,7 +149,7 @@ public abstract class AbstractMyrmidonTest */ protected void assertSameMessage( final String message, final Throwable throwable ) { - assertEquals( message, throwable.getMessage() ); + assertSameMessage( new String[] { message }, throwable ); } /** diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java index ef6f324c6..371e341da 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractProjectTest.java @@ -54,7 +54,7 @@ public class AbstractProjectTest // Need to set the context classloader - The default embeddor uses it Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); - final Logger logger = createLogger(); + final Logger logger = getLogger(); m_embeddor = new DefaultEmbeddor(); m_embeddor.enableLogging( logger ); diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java index 2dad31090..244c6a02d 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java @@ -14,7 +14,6 @@ import org.apache.aut.converter.Converter; import org.apache.avalon.framework.logger.LogEnabled; import org.apache.avalon.framework.logger.Logger; import org.apache.avalon.framework.service.DefaultServiceManager; -import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.myrmidon.AbstractMyrmidonTest; @@ -24,20 +23,19 @@ import org.apache.myrmidon.components.converter.DefaultConverterRegistry; import org.apache.myrmidon.components.converter.DefaultMasterConverter; import org.apache.myrmidon.components.deployer.DefaultDeployer; import org.apache.myrmidon.components.extensions.DefaultExtensionManager; +import org.apache.myrmidon.components.property.DefaultPropertyResolver; import org.apache.myrmidon.components.role.DefaultRoleManager; import org.apache.myrmidon.components.type.DefaultTypeManager; -import org.apache.myrmidon.components.property.DefaultPropertyResolver; import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; import org.apache.myrmidon.interfaces.configurer.Configurer; import org.apache.myrmidon.interfaces.converter.ConverterRegistry; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.extensions.ExtensionManager; +import org.apache.myrmidon.interfaces.property.PropertyResolver; import org.apache.myrmidon.interfaces.role.RoleInfo; import org.apache.myrmidon.interfaces.role.RoleManager; import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; -import org.apache.myrmidon.interfaces.type.TypeException; import org.apache.myrmidon.interfaces.type.TypeManager; -import org.apache.myrmidon.interfaces.property.PropertyResolver; /** * A base class for tests for the default components. @@ -48,7 +46,6 @@ public abstract class AbstractComponentTest extends AbstractMyrmidonTest { private DefaultServiceManager m_serviceManager; - private Logger m_logger; public AbstractComponentTest( final String name ) { @@ -58,95 +55,85 @@ public abstract class AbstractComponentTest /** * Returns the component manager containing the components to test. */ - protected final ServiceManager getServiceManager() - { - return m_serviceManager; - } - - protected final Logger getLogger() + protected final ServiceManager getServiceManager() throws Exception { - return m_logger; - } - - /** - * Returns the type manager. - */ - protected TypeManager getTypeManager() - throws ServiceException - { - return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); - } - - /** - * Setup the test case - prepares the set of components. - */ - protected void setUp() - throws Exception - { - m_logger = createLogger(); + if( m_serviceManager == null ) + { + Logger logger = getLogger(); - // Create the components - m_serviceManager = new DefaultServiceManager(); - List components = new ArrayList(); + // Create the components + m_serviceManager = new DefaultServiceManager(); + List components = new ArrayList(); - Object component = new DefaultMasterConverter(); - m_serviceManager.put( Converter.ROLE, component ); - components.add( component ); + Object component = new DefaultMasterConverter(); + m_serviceManager.put( Converter.ROLE, component ); + components.add( component ); - component = new DefaultConverterRegistry(); - m_serviceManager.put( ConverterRegistry.ROLE, component ); - components.add( component ); + component = new DefaultConverterRegistry(); + m_serviceManager.put( ConverterRegistry.ROLE, component ); + components.add( component ); - component = new DefaultTypeManager(); - m_serviceManager.put( TypeManager.ROLE, component ); - components.add( component ); + component = new DefaultTypeManager(); + m_serviceManager.put( TypeManager.ROLE, component ); + components.add( component ); - component = new DefaultConfigurer(); - m_serviceManager.put( Configurer.ROLE, component ); - components.add( component ); + component = new DefaultConfigurer(); + m_serviceManager.put( Configurer.ROLE, component ); + components.add( component ); - component = new DefaultDeployer(); - m_serviceManager.put( Deployer.ROLE, component ); - components.add( component ); + component = new DefaultDeployer(); + m_serviceManager.put( Deployer.ROLE, component ); + components.add( component ); - final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); - classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); - m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); - components.add( classLoaderMgr ); + final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); + classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); + m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); + components.add( classLoaderMgr ); - component = new DefaultExtensionManager(); - m_serviceManager.put( ExtensionManager.ROLE, component ); - components.add( component ); + component = new DefaultExtensionManager(); + m_serviceManager.put( ExtensionManager.ROLE, component ); + components.add( component ); - component = new DefaultRoleManager(); - m_serviceManager.put( RoleManager.ROLE, component ); - components.add( component ); + component = new DefaultRoleManager(); + m_serviceManager.put( RoleManager.ROLE, component ); + components.add( component ); - component = new DefaultPropertyResolver(); - m_serviceManager.put( PropertyResolver.ROLE, component ); - components.add( component ); + component = new DefaultPropertyResolver(); + m_serviceManager.put( PropertyResolver.ROLE, component ); + components.add( component ); - // Log enable the components - for( Iterator iterator = components.iterator(); iterator.hasNext(); ) - { - Object obj = iterator.next(); - if( obj instanceof LogEnabled ) + // Log enable the components + for( Iterator iterator = components.iterator(); iterator.hasNext(); ) { - final LogEnabled logEnabled = (LogEnabled)obj; - logEnabled.enableLogging( m_logger ); + Object obj = iterator.next(); + if( obj instanceof LogEnabled ) + { + final LogEnabled logEnabled = (LogEnabled)obj; + logEnabled.enableLogging( logger ); + } } - } - // Compose the components - for( Iterator iterator = components.iterator(); iterator.hasNext(); ) - { - Object obj = iterator.next(); - if( obj instanceof Serviceable ) + // Compose the components + for( Iterator iterator = components.iterator(); iterator.hasNext(); ) { - final Serviceable serviceable = (Serviceable)obj; - serviceable.service( m_serviceManager ); + Object obj = iterator.next(); + if( obj instanceof Serviceable ) + { + final Serviceable serviceable = (Serviceable)obj; + serviceable.service( m_serviceManager ); + } } } + return m_serviceManager; + } + + /** + * Returns the type manager. + */ + protected TypeManager getTypeManager() + throws Exception + { + return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); } /** @@ -179,7 +166,7 @@ public abstract class AbstractComponentTest protected void registerConverter( final Class converterClass, final Class sourceClass, final Class destClass ) - throws ServiceException, TypeException + throws Exception { ConverterRegistry converterRegistry = (ConverterRegistry)getServiceManager().lookup( ConverterRegistry.ROLE ); converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java index dfbcbcd94..00c706cca 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/builder/DefaultProjectBuilderTest.java @@ -8,9 +8,13 @@ package org.apache.myrmidon.components.builder; import java.io.File; +import java.util.Arrays; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.excalibur.io.FileUtil; import org.apache.myrmidon.AbstractMyrmidonTest; +import org.apache.myrmidon.interfaces.builder.ProjectException; +import org.apache.myrmidon.interfaces.model.Project; /** * Test cases for {@link DefaultProjectBuilder}. @@ -22,7 +26,7 @@ public class DefaultProjectBuilderTest extends AbstractMyrmidonTest { private final static Resources REZ - = ResourceManager.getPackageResources( DefaultProjectBuilder.class ); + = ResourceManager.getPackageResources( DefaultProjectBuilderTest.class ); private DefaultProjectBuilder m_builder; @@ -35,11 +39,227 @@ public class DefaultProjectBuilderTest { super.setUp(); m_builder = new DefaultProjectBuilder(); - m_builder.enableLogging( createLogger() ); + m_builder.enableLogging( getLogger() ); } /** - * Test validation of project and target names. + * Creates a project, with default values set. + */ + private DefaultProject createProject( final File projFile ) + { + final DefaultProject project = new DefaultProject(); + project.setProjectName( FileUtil.removeExtension( projFile.getName() ) ); + project.setBaseDirectory( getTestDirectory( "." ) ); + project.setDefaultTargetName( "main" ); + return project; + } + + /** + * Tests bad project file name. + */ + public void testProjectFileName() throws Exception + { + // Test with a file that does not exist + File projFile = getTestResource( "unknown.ant", false ); + + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.no-project-file.error" ) + }; + assertSameMessage( messages, e ); + } + + // Test with a directory + projFile = getTestDirectory( "some-dir" ); + + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.no-project-file.error" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Tests error reporting when the project file contains badly formed XML. + */ + public void testBadlyFormedFile() throws Exception + { + final File projFile = getTestResource( "bad-xml.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.project-parse.error" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Tests building a project with default values for project name, base dir + * and default target. + */ + public void testDefaults() throws Exception + { + // Build project + final File projFile = getTestResource( "defaults.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the project name. + */ + public void testProjectName() throws Exception + { + // Build project + final File projFile = getTestResource( "set-project-name.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + expected.setProjectName( "some-project" ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the base directory. + */ + public void testBaseDirectory() throws Exception + { + // Build project + final File projFile = getTestResource( "set-base-dir.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + final File baseDir = getTestDirectory( "other-base-dir" ); + expected.setBaseDirectory( baseDir ); + assertSameProject( expected, project ); + } + + /** + * Tests setting the default target name. + */ + public void testDefaultTarget() throws Exception + { + // Build project + final File projFile = getTestResource( "set-default-target.ant" ); + Project project = m_builder.build( projFile.getAbsolutePath() ); + + // Compare against expected project + DefaultProject expected = createProject( projFile ); + expected.setDefaultTargetName( "some-target" ); + assertSameProject( expected, project ); + } + + /** + * Tests missing, invalid and incompatible project version. + */ + public void testProjectVersion() throws Exception + { + // No version + File projFile = getTestResource( "no-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.version-missing.error" ) + }; + assertSameMessage( messages, e ); + } + + // Badly formed version + projFile = getTestResource( "bad-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.malformed.version", "ant2" ) + }; + assertSameMessage( messages, e ); + } + + // Incompatible version + projFile = getTestResource( "mismatched-version.ant" ); + try + { + m_builder.build( projFile.getAbsolutePath() ); + fail(); + } + catch( ProjectException e ) + { + final String[] messages = + { + REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), + REZ.getString( "ant.bad-version.error", "2.0.0", "1.0.2" ) + }; + assertSameMessage( messages, e ); + } + } + + /** + * Asserts that 2 projects are identical. + */ + protected void assertSameProject( final Project expected, + final Project project ) + { + assertEquals( expected.getProjectName(), project.getProjectName() ); + assertEquals( expected.getBaseDirectory(), project.getBaseDirectory() ); + assertEquals( expected.getDefaultTargetName(), project.getDefaultTargetName() ); + + // TODO - make sure each of the projects are the same + assertTrue( Arrays.equals( expected.getProjectNames(), project.getProjectNames() ) ); + + // TODO - make sure the implicit targets are the same + + // TODO - make sure each of the targets are the same + assertTrue( Arrays.equals( expected.getTargetNames(), project.getTargetNames() ) ); + + // TODO - implement TypeLib.equals(), or use a comparator + assertTrue( Arrays.equals( expected.getTypeLibs(), project.getTypeLibs() ) ); + } + + /** + * Tests validation of project and target names. */ public void testNameValidation() throws Exception { @@ -52,7 +272,12 @@ public class DefaultProjectBuilderTest } catch( Exception e ) { - assertSameMessage( REZ.getString( "ant.project-bad-name.error" ), e ); + final String[] messages = + { + REZ.getString( "ant.project-build.error", badProjectFile.getAbsolutePath() ), + REZ.getString( "ant.project-bad-name.error" ) + }; + assertSameMessage( messages, e ); } // Check bad target name @@ -64,7 +289,13 @@ public class DefaultProjectBuilderTest } catch( Exception e ) { - // TODO - check error message + final String[] messages = + { + REZ.getString( "ant.project-build.error", badTargetFile.getAbsolutePath() ), + // TODO - check error message + null + }; + assertSameMessage( messages, e ); } } } diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java similarity index 70% rename from proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java rename to proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java index e92675b83..9e79a0d2b 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/AbstractPropertyResolverTest.java @@ -5,53 +5,51 @@ * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ -package org.apache.myrmidon.components.workspace; +package org.apache.myrmidon.components.property; import java.io.File; import java.util.Date; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.context.Context; +import org.apache.myrmidon.AbstractMyrmidonTest; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.components.AbstractComponentTest; -import org.apache.myrmidon.components.property.DefaultPropertyResolver; +import org.apache.myrmidon.components.workspace.DefaultTaskContext; import org.apache.myrmidon.interfaces.property.PropertyResolver; /** - * Functional tests for {@link DefaultPropertyResolver}. + * General-purpose property resolver test cases. * - * @author Darrell DeBoer + * @author Adam Murdoch * @version $Revision$ $Date$ */ -public class DefaultPropertyResolverTest - extends AbstractComponentTest +public abstract class AbstractPropertyResolverTest + extends AbstractMyrmidonTest { protected final static Resources REZ - = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); + = ResourceManager.getPackageResources( AbstractPropertyResolverTest.class ); protected PropertyResolver m_resolver; protected DefaultTaskContext m_context; - public DefaultPropertyResolverTest( String name ) + public AbstractPropertyResolverTest( String name ) { super( name ); } protected void setUp() throws Exception { - super.setUp(); - m_resolver = createResolver(); - m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); + m_context = new DefaultTaskContext( null, null, getLogger() ); m_context.setProperty( "intProp", new Integer( 333 ) ); m_context.setProperty( "stringProp", "String property" ); } - protected PropertyResolver createResolver() - { - return new DefaultPropertyResolver(); - } + /** + * Creates the resolver to test. + */ + protected abstract PropertyResolver createResolver(); /** * Test property resolution with various different typed properties. @@ -73,7 +71,7 @@ public class DefaultPropertyResolverTest throws Exception { m_context.setProperty( "typedProp", propObject ); - String propString = propObject.toString(); + final String propString = propObject.toString(); doTestResolution( "${typedProp}", propObject, m_context ); doTestResolution( "${typedProp} with following text", @@ -96,23 +94,6 @@ public class DefaultPropertyResolverTest doTestResolution( "before ${prop2} between ${prop1} after", "before value2 between value1 after", m_context ); doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); - - } - - /** - * Tests handing undefined property. - */ - public void testUndefinedProp() throws Exception - { - String undefinedProp = "undefinedProperty"; - doTestFailure( "${" + undefinedProp + "}", - REZ.getString( "prop.missing-value.error", undefinedProp ), - m_context ); - - //TODO - "" should be disallowed as a property name - doTestFailure( "${}", - REZ.getString( "prop.missing-value.error", "" ), - m_context ); } /** @@ -131,18 +112,17 @@ public class DefaultPropertyResolverTest /* TODO - need to handle these cases. */ // testFailure( "${bad${}", "", m_context ); // testFailure( "${ }", "", m_context ); - } /** * Resolves the property using the supplied context, and checks the result. */ - protected void doTestResolution( String value, - Object expected, - Context context ) + protected void doTestResolution( final String value, + final Object expected, + final Context context ) throws Exception { - Object resolved = m_resolver.resolveProperties( value, context ); + final Object resolved = m_resolver.resolveProperties( value, context ); assertEquals( expected, resolved ); } @@ -151,9 +131,9 @@ public class DefaultPropertyResolverTest * Attempts to resolve the value using the supplied context, expecting to * fail with the supplied error message. */ - protected void doTestFailure( String value, - String expectedErrorMessage, - Context context ) + protected void doTestFailure( final String value, + final String expectedErrorMessage, + final Context context ) { try { diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java similarity index 77% rename from proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java rename to proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java index ae5cbabdf..a0779291f 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/ClassicPropertyResolverTest.java @@ -5,19 +5,18 @@ * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ -package org.apache.myrmidon.components.workspace; +package org.apache.myrmidon.components.property; import org.apache.myrmidon.interfaces.property.PropertyResolver; -import org.apache.myrmidon.components.property.ClassicPropertyResolver; /** - * A test for {@link ClassicPropertyResolver} + * A test for {@link ClassicPropertyResolver}. * * @author Darrell DeBoer * @version $Revision$ $Date$ */ public class ClassicPropertyResolverTest - extends DefaultPropertyResolverTest + extends AbstractPropertyResolverTest { public ClassicPropertyResolverTest( String name ) { @@ -34,8 +33,7 @@ public class ClassicPropertyResolverTest */ public void testUndefinedProp() throws Exception { - String undefinedProp = "undefinedProperty"; - + final String undefinedProp = "undefinedProperty"; final String propRef = "${" + undefinedProp + "}"; doTestResolution( propRef, propRef, m_context ); } diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java new file mode 100644 index 000000000..4d1f2198d --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/property/DefaultPropertyResolverTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.components.property; + +import org.apache.myrmidon.interfaces.property.PropertyResolver; + +/** + * Functional tests for {@link DefaultPropertyResolver}. + * + * @author Darrell DeBoer + * @version $Revision$ $Date$ + */ +public class DefaultPropertyResolverTest + extends AbstractPropertyResolverTest +{ + public DefaultPropertyResolverTest( String name ) + { + super( name ); + } + + protected PropertyResolver createResolver() + { + return new DefaultPropertyResolver(); + } + + /** + * Tests handing undefined property. + */ + public void testUndefinedProp() throws Exception + { + final String undefinedProp = "undefinedProperty"; + doTestFailure( "${" + undefinedProp + "}", + REZ.getString( "prop.missing-value.error", undefinedProp ), + m_context ); + + //TODO - "" should be disallowed as a property name + doTestFailure( "${}", + REZ.getString( "prop.missing-value.error", "" ), + m_context ); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java index 8ce1fb3cb..c2b69bdff 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java @@ -44,11 +44,9 @@ public class InstantiatingServiceManagerTest protected void setUp() throws Exception { - super.setUp(); - // Set-up the service manager m_serviceManager = new InstantiatingServiceManager(); - m_serviceManager.enableLogging( createLogger() ); + m_serviceManager.enableLogging( getLogger() ); m_serviceManager.service( getServiceManager() ); m_serviceManager.parameterize( m_parameters ); }